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进行多用户的搜索请求 下面是官网的一段代码
importorg.elasticsearch.xpack.client.PreBuiltXPackTransportClient;
...
TransportClientclient = newPreBuiltXPackTransportClient(Settings.builder()
.put("cluster.name", "myClusterName")
.put("xpack.security.user", "transport_client_user:x-pack-test-password")
...
.build())
.addTransportAddress(newTransportAddress("localhost", 9300))
.addTransportAddress(newTransportAddress("localhost", 9301));每一个transport client都需要将用户名和密码写死在配置里面,如果要使用多用户进行请求的话,就不得不建立多个transport client连接,这种方式感觉很傻,尽管我之前写过用common-pool2组件管理transport client连接,但是一想到以后会有成千上万的用户访问就要建立成千上万的连接,想想都要爆炸💥
但是rest high level client就没有这个问题,它通过RequestOptions携带用户的token信息进行搜索请求,不同的用户搜索只需要分配不同的RequestOptions就行了
privatestaticRequestOptionsrequestOptions(Stringtoken) {
//设置允许返回的最大字节数HttpAsyncResponseConsumerFactoryresponseConsumerFactory = newHttpAsyncResponseConsumerFactory
.HeapBufferedResponseConsumerFactory(Integer.MAX_VALUE);
RequestOptions.Builderbuilder = RequestOptions.DEFAULT.toBuilder();
builder.setHttpAsyncResponseConsumerFactory(responseConsumerFactory);
builder.addHeader("Authorization", "Basic " + token);
returnbuilder.build();
}
publicMap<String, Object> get(Stringcluster,Stringindex,Stringtype, Stringid, Stringrouting, Stringtoken) throwsIOException {
GetRequestgetRequest = newGetRequest(index, type, id).routing(routing);
GetResponsegetResponse = getRestHighLevelClient(cluster).get(getRequest, requestOptions(token));
returngetResponse.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了解,或者自己看源码(推荐,原作者的代码很优秀)
@TestpublicvoidtestParseFromMethodSource(){
Stringsql="select * from fruits where match(name,'apple','prefix_length:21') and term(color,'red')";
ElasticSql2DslParsersql2DslParser=newElasticSql2DslParser();
ElasticSqlParseResultparseResult = sql2DslParser.parse(sql,newString[]{"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
}
}
}@TestpublicvoidtestParseLimit(){
Stringsql="select * from fruits where match_phrase(name,'apple') and term(color,'red') limit 2,9";
ElasticSql2DslParsersql2DslParser=newElasticSql2DslParser();
ElasticSqlParseResultparseResult = sql2DslParser.parse(sql,newString[]{"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'
@TestpublicvoidtestParseTermsAgg(){
Stringsql="select * from fruits where name is not null and color is not null group by terms(weight,5000),terms(color,600)";
ElasticSql2DslParsersql2DslParser=newElasticSql2DslParser();
ElasticSqlParseResultparseResult = sql2DslParser.parse(sql,newString[]{"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"
} ]
}
}
}
}publicstaticvoidmain(String[] args) {
Stringsql="DELETE from fruits where match_all() limit 1100";
ElasticSql2DslParserelasticSql2DslParser=newElasticSql2DslParser();
ElasticSqlParseResultelasticSqlParseResult = elasticSql2DslParser.parse(sql, newString[]{"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