PLEASE MOVE TO elasticsearch-sql
这个版本的elasticsearch-sql是基于Alibaba的Druid中的SqlParser组件,由于elasticsearch许多功能并不适合使用sql表达,导致实现elasticsearch一些高级功能的时候越来越受到SqlParser的限制,所以这个版本的elasticsearch-sql仅供交流,现已另启一个项目👉elasticsearch-sql,使用Antlr4来解析sql生成dsl,使elasticsql完全可控,并将提供多语言的支持,尽请期待!
<dependency>
<groupId>io.github.iamazy.elasticsearch.dsl</groupId>
<artifactId>elasticsearch-sql</artifactId>
<version>${isql-version}</version>
</dependency>
elasticsearch version | latest version | remark | isql version |
---|---|---|---|
6.x | 6.6.0 | 6.6.0.1 | |
6.x | 6.6.1 | 6.6.1.1 | |
6.x | 6.6.2 | 6.6.2.1 | |
6.x | 6.7.0 | 6.7.0.1 | |
6.x | 6.7.1 | 6.7.1.1 | |
7.x | 7.0.0 | 7.0.0.2 | |
7.x | 7.0.1 | 7.0.1.1 | |
7.x | 7.1.0 | 7.1.0.1 | |
7.x | 7.1.1 | 7.1.1.1 | |
7.x | 7.2.0 | 7.2.0.1 |
Elasticsearch {6.x,7.x}
./bin/elasticsearch-plugin install https://github.com/iamazy/elasticsearch-sql/releases/download/{isql-version}/elasticsearch-sql-plugin-{isql-version}.zip
POST _isql
{
"sql":"select * from fruit"
}
POST _isql
{
"sql":"desc fruit"
}
POST _isql
{
"sql":"desc fruit/name"
}
POST _isql/_explain
{
"sql":"select * from fruit"
}
2019-3-6:修复原版Nested类型的nested path识别错误的问题
2019-3-7:删除了大部分无用的代码,添加了geo_distance聚类方法
2019-3-25: 聚类使用递归实现添加多层嵌套聚类方式([>]表示嵌套聚类[,]表示同级聚类),具体用法见test目录
2019-3-26: 添加scroll id深度分页
2019-3-28: 更新nested功能,支持双层嵌套类型(再多就要考虑数据结构是否合理了)
2019-4-8: 添加高亮显示
2019-4-11: 添加Function Score
2019-4-24: 将elasticsearch-sql添加为elasticsearch插件
2019-4-28: 添加like not like 查询
2019-5-5: 添加desc语法获取index(或者index/field)的mapping,无法直接获取实际的mapping,必须结合restClient使用,且desc后面只能加一个index的名称
2019-5-8: 添加excludes字段(在字段前加[^])
2019-6-5: 解决了索引名带中划线[-]报错的bug
elasticsearch-sql | es version |
---|---|
master | 6.6.0 |
master | 6.6.2 |
master | 6.7.0 |
master | 6.7.1 |
master | 7.0.0 |
master | 7.0.1 |
master | 7.1.1 |
master | 7.2.0 |
首先感谢elasticsearch-query-toolkit
的作者gitchennan
,elasticsearch-sql基于gitchennan
的elasticsearch-query-toolkit
,并在其中稍作修改和添加部分功能,再次感谢gitchennan
哈哈哈哈哈
gitchennan
的github地址:elasticsearch-query-toolkit
elasticsearch-sql是一个基于sql查询的elasticsearch编程工具包,支持sql生成elasticsearch dsl,去掉了elasticsearch-query-toolkit
中与Spring,Mybatis
集成的部分,有需要的话请参照elasticsearch-query-toolkit
1)elasticsearch-sql是基于Java Rest High Level Client构建elasticsearch查询的,支持elasticsearch原生rest client调用以及第三方http请求
抛弃elasticsearch传统的transport连接方式改用rest high level连接方式不仅仅是因为官方建议,而是在结合x-pack组件进行鉴权的时候更加方便 本人不知道在transport连接方式中如何复用transport client进行多用户的搜索请求 下面是官网的一段代码
import org.elasticsearch.xpack.client.PreBuiltXPackTransportClient;
...
TransportClient client = new PreBuiltXPackTransportClient(Settings.builder()
.put("cluster.name", "myClusterName")
.put("xpack.security.user", "transport_client_user:x-pack-test-password")
...
.build())
.addTransportAddress(new TransportAddress("localhost", 9300))
.addTransportAddress(new TransportAddress("localhost", 9301));
每一个transport client都需要将用户名和密码写死在配置里面,如果要使用多用户进行请求的话,就不得不建立多个transport client连接,这种方式感觉很傻,尽管我之前写过用common-pool2组件管理transport client连接,但是一想到以后会有成千上万的用户访问就要建立成千上万的连接,想想都要爆炸💥
但是rest high level client就没有这个问题,它通过RequestOptions
携带用户的token信息进行搜索请求,不同的用户搜索只需要分配不同的RequestOptions
就行了
private static RequestOptions requestOptions(String token) {
//设置允许返回的最大字节数
HttpAsyncResponseConsumerFactory responseConsumerFactory = new HttpAsyncResponseConsumerFactory
.HeapBufferedResponseConsumerFactory(Integer.MAX_VALUE);
RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();
builder.setHttpAsyncResponseConsumerFactory(responseConsumerFactory);
builder.addHeader("Authorization", "Basic " + token);
return builder.build();
}
public Map<String, Object> get(String cluster,String index,String type, String id, String routing, String token) throws IOException {
GetRequest getRequest = new GetRequest(index, type, id).routing(routing);
GetResponse getResponse = getRestHighLevelClient(cluster).get(getRequest, requestOptions(token));
return getResponse.getSourceAsMap();
}
简单又方便,简直不要太棒了好吧
🐷也许是我的使用问题,如果有人知道如何使用transport client进行多用户的搜索请求,麻烦告诉我一下,我还挺好奇的
我是向https://github.com/NLPchina/elasticsearch-sql的开发团队看齐的,功能点会慢慢的一点一点的添加的
-
SQL Select
-
SQL Where
-
SQL Order by (Asc & Desc)
-
SQL Group by (Terms & Range)
-
SQL And & Or
-
SQL In
-
SQL Between And
-
SQL Is
-
SQL Not
-
SQL Null
-
SQL Nvl
-
SQL Max
-
SQL Min
-
SQL Sum
-
SQL Avg
-
SQL > & < & >= & <=
-
ES FullText
-
ES Match
-
ES MultiMatch
-
ES QueryString
-
ES SimpleQueryString
-
ES HasParent
-
ES HasChild
-
ES Join
-
ES Script
-
ES Fuzzy
-
ES Prefix
-
ES Regex
-
ES Term
-
ES Wildcard
-
ES Routing
-
ES Nested
-
ES Include[fields]
-
ES From
-
ES Size
-
ES Range(Number,Date)
- ES MatchAll
- ES MatchPhrase
- ES MatchPhrasePrefix
- ES DeleteByQuery
- ES Cardinality (目前不支持Script的方式)
- ES TopHits
- ES Nested (elasticsearch-query-toolkit中nested表达方式不合理,已修正)
- ES GeoDistance
- 支持嵌套深层聚类
- ES Scroll Id
- ES 支持双层嵌套查询(nested(nested))现在以及以后也不会支持三层以上的嵌套查询
- ES Highlighter
- ES Boosting
- ES Function Score
- SQL Like
- SQL Desc
- ES Excludes
- ES Highlighter
- elasticsearch-sql[NLPChina]组件中我未添加的功能!!!
☀️未来的想法是将功能完善的跟NLPChina团队一样多嘻嘻
提供几个SQL转DSL的例子(在源码test文件夹里),其他部分你们需要去elasticsearch-query-toolkit了解,或者自己看源码(推荐,原作者的代码很优秀)
@Test
public void testParseFromMethodSource(){
String sql="select * from fruits where match(name,'apple','prefix_length:21') and term(color,'red')";
ElasticSql2DslParser sql2DslParser=new ElasticSql2DslParser();
ElasticSqlParseResult parseResult = sql2DslParser.parse(sql,new String[]{"name","color"});
System.out.println(parseResult.toPrettyDsl(parseResult.toRequest()));
}
{
"from" : 0,
"size" : 15,
"query" : {
"bool" : {
"filter" : [ {
"bool" : {
"must" : [ {
"match" : {
"name" : {
"query" : "apple",
"operator" : "OR",
"prefix_length" : 21,
"max_expansions" : 50,
"fuzzy_transpositions" : true,
"lenient" : false,
"zero_terms_query" : "NONE",
"auto_generate_synonyms_phrase_query" : true,
"boost" : 1.0
}
}
}, {
"term" : {
"color" : {
"value" : "red",
"boost" : 1.0
}
}
} ],
"adjust_pure_negative" : true,
"boost" : 1.0
}
} ],
"adjust_pure_negative" : true,
"boost" : 1.0
}
}
}
@Test
public void testParseLimit(){
String sql="select * from fruits where match_phrase(name,'apple') and term(color,'red') limit 2,9";
ElasticSql2DslParser sql2DslParser=new ElasticSql2DslParser();
ElasticSqlParseResult parseResult = sql2DslParser.parse(sql,new String[]{"name","color"});
System.out.println(parseResult.toPrettyDsl(parseResult.toRequest()));
}
{
"from" : 2,
"size" : 9,
"query" : {
"bool" : {
"filter" : [ {
"bool" : {
"must" : [ {
"match_phrase" : {
"name" : {
"query" : "apple",
"slop" : 0,
"zero_terms_query" : "NONE",
"boost" : 1.0
}
}
}, {
"term" : {
"color" : {
"value" : "red",
"boost" : 1.0
}
}
} ],
"adjust_pure_negative" : true,
"boost" : 1.0
}
} ],
"adjust_pure_negative" : true,
"boost" : 1.0
}
}
}
🐷Term(a,b) 也可以在SQL中直接写成a='b'
@Test
public void testParseTermsAgg(){
String sql="select * from fruits where name is not null and color is not null group by terms(weight,5000),terms(color,600)";
ElasticSql2DslParser sql2DslParser=new ElasticSql2DslParser();
ElasticSqlParseResult parseResult = sql2DslParser.parse(sql,new String[]{"name","color"});
System.out.println(parseResult.toPrettyDsl(parseResult.toRequest()));
}
"from" : 0,
"size" : 15,
"query" : {
"bool" : {
"filter" : [ {
"bool" : {
"must" : [ {
"exists" : {
"field" : "name",
"boost" : 1.0
}
}, {
"exists" : {
"field" : "color",
"boost" : 1.0
}
} ],
"adjust_pure_negative" : true,
"boost" : 1.0
}
} ],
"adjust_pure_negative" : true,
"boost" : 1.0
}
},
"aggregations" : {
"weight" : {
"terms" : {
"field" : "weight",
"size" : 5000,
"shard_size" : 10000,
"min_doc_count" : 1,
"shard_min_doc_count" : 1,
"show_term_doc_count_error" : false,
"order" : [ {
"_count" : "desc"
}, {
"_key" : "asc"
} ]
}
},
"color" : {
"terms" : {
"field" : "color",
"size" : 600,
"shard_size" : 1200,
"min_doc_count" : 1,
"shard_min_doc_count" : 1,
"show_term_doc_count_error" : false,
"order" : [ {
"_count" : "desc"
}, {
"_key" : "asc"
} ]
}
}
}
}
public static void main(String[] args) {
String sql="DELETE from fruits where match_all() limit 1100";
ElasticSql2DslParser elasticSql2DslParser=new ElasticSql2DslParser();
ElasticSqlParseResult elasticSqlParseResult = elasticSql2DslParser.parse(sql, new String[]{"port"});
System.out.println(elasticSqlParseResult.toPrettyDsl(elasticSqlParseResult.toDelRequest().getSearchRequest()));
}
{
"size" : 1000,
"query" : {
"bool" : {
"must" : [ {
"match_all" : {
"boost" : 1.0
}
} ],
"adjust_pure_negative" : true,
"boost" : 1.0
}
},
"_source" : false
}
🐷 DSL里的size=1000和Java中的limit 1100
含义不一样
size=1000 是DeleteByQueryRequest中的SearchRequest的Size,默认为1000
limit 1100 设置的是DeleteByQueryRequest的Size,只是在DSL中没有显示
为了表征nested path这个属性,采用 $ 符号指明
nested path必须以 $ 在为nested类型的属性之前结尾(非常重要)
🐖:一个嵌套表达式最多包含2个$符号
重要:以product
的apple
为例,apple
为nested
类型,则查询时的nested path应该为product.apple
以下两种写法均正确
product$apple.name
下面这几种写法错误
$product$apple.name
product.apple$name
$product.apple$name
$product$apple$name
product$apple$name
Nested结构参照
"product" : {
"properties" : {
"apple" : {
"type" : "nested",
"properties" : {
"name" : {
"type" : "text"
},
"price" : {
"type" : "double"
}
}
}
}
}
🌹其余的请去test目录下找吧
欢迎大家提issue