From a18fff9bbcbe31d045654917cc8093c3aad4a171 Mon Sep 17 00:00:00 2001 From: jiangnan <1448588084@qq.com> Date: Sun, 5 May 2019 18:52:57 +0800 Subject: [PATCH] update version --- CHANGELOG | 3 ++ README.md | 15 ++++++ pom.xml | 2 +- .../dsl/plugin/RestSqlAction.java | 54 +++++++++++-------- .../dsl/sql/model/ElasticSqlParseResult.java | 29 +++++++--- .../dsl/sql/parser/ElasticSql2DslParser.java | 22 +++++++- .../method/mapping/MappingQueryParser.java | 39 ++++++++++++++ .../elasticsearch/dsl/sql/DescTest.java | 20 +++++++ 8 files changed, 153 insertions(+), 31 deletions(-) create mode 100644 src/main/java/io/github/iamazy/elasticsearch/dsl/sql/parser/query/method/mapping/MappingQueryParser.java create mode 100644 src/test/java/io/github/iamazy/elasticsearch/dsl/sql/DescTest.java diff --git a/CHANGELOG b/CHANGELOG index 5a8a58e..63e20d8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -15,3 +15,6 @@ 2019-4-24: 将elasticsearch-sql添加为elasticsearch插件 2019-4-28: 添加like not like 查询 + +2019-5-5: 添加desc语法获取index(或者index/field)的mapping,无法直接获取实际的mapping,必须结合restClient使用,且desc后面只能加一个index的名称 + diff --git a/README.md b/README.md index 20940a3..339a62c 100755 --- a/README.md +++ b/README.md @@ -41,6 +41,20 @@ POST _isql "sql":"select * from fruit" } ``` +###### 语法:desc [index] +``` +POST _isql +{ + "sql":"desc fruit" +} +``` +###### 语法:desc [index]/[field] +``` +POST _isql +{ + "sql":"desc fruit/name" +} +``` ##### 2. 将sql解析成elasticsearch的dsl ``` @@ -66,6 +80,7 @@ CHANGELOG 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的名称
[CHANGELOG](https://github.com/iamazy/elasticsearch-sql/edit/master/CHANGELOG) diff --git a/pom.xml b/pom.xml index 083b4cc..593ce89 100755 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ https://github.com/iamazy/elasticsearch-sql - 7.0.1 + 7.0.0 1.8 isql io.github.iamazy.elasticsearch.dsl.plugin.SqlPlugin diff --git a/src/main/java/io/github/iamazy/elasticsearch/dsl/plugin/RestSqlAction.java b/src/main/java/io/github/iamazy/elasticsearch/dsl/plugin/RestSqlAction.java index 400195d..ea9a06c 100644 --- a/src/main/java/io/github/iamazy/elasticsearch/dsl/plugin/RestSqlAction.java +++ b/src/main/java/io/github/iamazy/elasticsearch/dsl/plugin/RestSqlAction.java @@ -1,15 +1,15 @@ package io.github.iamazy.elasticsearch.dsl.plugin; +import com.carrotsearch.hppc.cursors.ObjectObjectCursor; import io.github.iamazy.elasticsearch.dsl.sql.exception.ElasticSql2DslException; import io.github.iamazy.elasticsearch.dsl.sql.model.ElasticSqlParseResult; import io.github.iamazy.elasticsearch.dsl.sql.parser.ElasticSql2DslParser; import org.apache.commons.lang3.StringUtils; import org.elasticsearch.client.node.NodeClient; +import org.elasticsearch.cluster.metadata.MappingMetaData; +import org.elasticsearch.common.collect.ImmutableOpenMap; import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.common.xcontent.XContentFactory; -import org.elasticsearch.common.xcontent.XContentParser; -import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.common.xcontent.*; import org.elasticsearch.rest.*; import java.io.IOException; @@ -22,12 +22,12 @@ **/ public class RestSqlAction extends BaseRestHandler { - RestSqlAction(Settings settings, RestController restController){ + RestSqlAction(Settings settings, RestController restController) { super(settings); - restController.registerHandler(RestRequest.Method.POST,"/_isql/_explain",this); - restController.registerHandler(RestRequest.Method.GET,"/_isql/_explain",this); - restController.registerHandler(RestRequest.Method.POST,"/_isql",this); - restController.registerHandler(RestRequest.Method.GET,"/_isql",this); + restController.registerHandler(RestRequest.Method.POST, "/_isql/_explain", this); + restController.registerHandler(RestRequest.Method.GET, "/_isql/_explain", this); + restController.registerHandler(RestRequest.Method.POST, "/_isql", this); + restController.registerHandler(RestRequest.Method.GET, "/_isql", this); } @@ -38,26 +38,36 @@ public String getName() { @Override protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient nodeClient) throws IOException { - try(XContentParser parser=restRequest.contentOrSourceParamParser()){ - parser.mapStrings().forEach((k,v)->restRequest.params().putIfAbsent(k,v)); - }catch (IOException e){ - return channel -> channel.sendResponse(new BytesRestResponse(RestStatus.BAD_REQUEST,XContentType.JSON.mediaType(),"please use json format params, like: {\"sql\":\"select * from test\"}")); + try (XContentParser parser = restRequest.contentOrSourceParamParser()) { + parser.mapStrings().forEach((k, v) -> restRequest.params().putIfAbsent(k, v)); + } catch (IOException e) { + return channel -> channel.sendResponse(new BytesRestResponse(RestStatus.BAD_REQUEST, XContentType.JSON.mediaType(), "please use json format params, like: {\"sql\":\"select * from test\"}")); } try { - String sql=restRequest.param("sql"); - if(StringUtils.isBlank(sql)){ - return channel -> channel.sendResponse(new BytesRestResponse(RestStatus.BAD_REQUEST,XContentType.JSON.mediaType(),"{\"error\":\"sql语句不能为空!!!\"}")); + String sql = restRequest.param("sql"); + if (StringUtils.isBlank(sql)) { + return channel -> channel.sendResponse(new BytesRestResponse(RestStatus.BAD_REQUEST, XContentType.JSON.mediaType(), "{\"error\":\"sql语句不能为空!!!\"}")); } - ElasticSql2DslParser sql2DslParser=new ElasticSql2DslParser(); + ElasticSql2DslParser sql2DslParser = new ElasticSql2DslParser(); ElasticSqlParseResult parseResult = sql2DslParser.parse(sql); XContentBuilder builder = XContentFactory.jsonBuilder().prettyPrint(); - if(restRequest.path().endsWith("/_explain")){ + if (restRequest.path().endsWith("/_explain")) { return channel -> channel.sendResponse(new BytesRestResponse(RestStatus.OK, builder.value(parseResult.toRequest().source()))); - }else{ - return channel -> channel.sendResponse(new BytesRestResponse(RestStatus.OK,builder.value(nodeClient.search(parseResult.toRequest()).actionGet()))); + } else { + if (parseResult.toFieldMapping() != null) { + return channel -> channel.sendResponse(new BytesRestResponse(RestStatus.OK, builder.value(nodeClient.admin().indices().getFieldMappings(parseResult.toFieldMapping()).actionGet()))); + } else if (parseResult.toMapping()!=null) { + ImmutableOpenMap objectObjectCursors = nodeClient.admin().indices().getMappings(parseResult.toMapping()).actionGet().mappings().get(parseResult.getIndices().get(0)); + for (ObjectObjectCursor objectObjectCursor : objectObjectCursors) { + return channel -> channel.sendResponse(new BytesRestResponse(RestStatus.OK, builder.value(objectObjectCursor.value.getSourceAsMap()))); + } + throw new ElasticSql2DslException("sql语句解析失败!!!"); + } else { + return channel -> channel.sendResponse(new BytesRestResponse(RestStatus.OK, builder.value(nodeClient.search(parseResult.toRequest()).actionGet()))); + } } - }catch (ElasticSql2DslException e){ - return channel -> channel.sendResponse(new BytesRestResponse(RestStatus.INTERNAL_SERVER_ERROR,XContentType.JSON.mediaType(),"{\"error\":\""+e.getMessage()+"\"}")); + } catch (ElasticSql2DslException e) { + return channel -> channel.sendResponse(new BytesRestResponse(RestStatus.INTERNAL_SERVER_ERROR, XContentType.JSON.mediaType(), "{\"error\":\"" + e.getMessage() + "\"}")); } } diff --git a/src/main/java/io/github/iamazy/elasticsearch/dsl/sql/model/ElasticSqlParseResult.java b/src/main/java/io/github/iamazy/elasticsearch/dsl/sql/model/ElasticSqlParseResult.java index d0cc98e..69492ae 100644 --- a/src/main/java/io/github/iamazy/elasticsearch/dsl/sql/model/ElasticSqlParseResult.java +++ b/src/main/java/io/github/iamazy/elasticsearch/dsl/sql/model/ElasticSqlParseResult.java @@ -8,6 +8,8 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; +import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsRequest; +import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchScrollRequest; @@ -43,7 +45,7 @@ public class ElasticSqlParseResult { private String scrollId; private List indices; -// private String type = "_doc"; + private String type = "_doc"; private String queryAs; /** * 需要高亮显示的字段 @@ -57,12 +59,15 @@ public class ElasticSqlParseResult { private transient List groupBy; private transient SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); + private GetMappingsRequest mappingsRequest; + private GetFieldMappingsRequest fieldMappingsRequest; + public DeleteByQueryRequest toDelRequest() { DeleteByQueryRequest deleteByQueryRequest = new DeleteByQueryRequest(toRequest().indices()); deleteByQueryRequest.setQuery(searchSourceBuilder.query()); -// if (StringUtils.isNotBlank(type)) { -// deleteByQueryRequest.types(type); -// } + if (StringUtils.isNotBlank(type)) { + deleteByQueryRequest.types(type); + } if (CollectionUtils.isNotEmpty(routingBy)) { deleteByQueryRequest.setRouting(routingBy.get(0)); } @@ -75,6 +80,14 @@ public DeleteByQueryRequest toDelRequest() { return deleteByQueryRequest; } + public GetFieldMappingsRequest toFieldMapping(){ + return fieldMappingsRequest; + } + + public GetMappingsRequest toMapping(){ + return mappingsRequest; + } + public SearchResponse toResponse(RestHighLevelClient restHighLevelClient, RequestOptions requestOptions) throws IOException { if (StringUtils.isNotBlank(scrollExpire) && StringUtils.isBlank(scrollId)) { return restHighLevelClient.search(toRequest(), requestOptions); @@ -93,9 +106,9 @@ public SearchRequest toRequest() { if (CollectionUtils.isNotEmpty(indices)) { searchRequest.indices(indices.toArray(new String[0])); } -// if (StringUtils.isNotBlank(type)) { -// searchRequest.types(type); -// } + if (StringUtils.isNotBlank(type)) { + searchRequest.types(type); + } if (from < 0) { @@ -112,6 +125,7 @@ public SearchRequest toRequest() { searchSourceBuilder.size(size); } + if(CollectionUtils.isNotEmpty(highlighter)) { HighlightBuilder highlightBuilder = HighlightBuilders.highlighter(highlighter); searchSourceBuilder.highlighter(highlightBuilder); @@ -156,6 +170,7 @@ public SearchRequest toRequest() { final Scroll scroll = new Scroll(TimeValue.parseTimeValue(scrollExpire, StringUtils.EMPTY)); searchRequest.scroll(scroll); } + return searchRequest.source(searchSourceBuilder); } diff --git a/src/main/java/io/github/iamazy/elasticsearch/dsl/sql/parser/ElasticSql2DslParser.java b/src/main/java/io/github/iamazy/elasticsearch/dsl/sql/parser/ElasticSql2DslParser.java index 50eccd7..5c851a2 100644 --- a/src/main/java/io/github/iamazy/elasticsearch/dsl/sql/parser/ElasticSql2DslParser.java +++ b/src/main/java/io/github/iamazy/elasticsearch/dsl/sql/parser/ElasticSql2DslParser.java @@ -13,11 +13,15 @@ import io.github.iamazy.elasticsearch.dsl.sql.druid.ElasticSqlSelectQueryBlock; import io.github.iamazy.elasticsearch.dsl.sql.exception.ElasticSql2DslException; import io.github.iamazy.elasticsearch.dsl.sql.parser.aggs.GroupByAggregationParser; +import io.github.iamazy.elasticsearch.dsl.sql.parser.query.method.mapping.MappingQueryParser; import io.github.iamazy.elasticsearch.dsl.sql.parser.sql.*; import io.github.iamazy.elasticsearch.dsl.sql.model.ElasticDslContext; import io.github.iamazy.elasticsearch.dsl.sql.model.ElasticSqlParseResult; +import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsRequest; +import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest; +import java.util.Arrays; import java.util.List; /** @@ -42,6 +46,22 @@ public ElasticSqlParseResult parse(String sql) throws ElasticSql2DslException { elasticDslContext.getParseResult().setSize(((SQLIntegerExpr) sqlLimit.getRowCount()).getNumber().intValue()); return elasticDslContext.getParseResult(); } + case DESC:{ + Object mappingsRequest = MappingQueryParser.parse(sql); + ElasticDslContext elasticDslContext=new ElasticDslContext(null); + if(mappingsRequest instanceof GetMappingsRequest) { + GetMappingsRequest getMappingsRequest=(GetMappingsRequest) mappingsRequest; + elasticDslContext.getParseResult().setMappingsRequest(getMappingsRequest); + elasticDslContext.getParseResult().setIndices(Arrays.asList(getMappingsRequest.indices())); + }else if(mappingsRequest instanceof GetFieldMappingsRequest) { + GetFieldMappingsRequest getFieldMappingsRequest=(GetFieldMappingsRequest) mappingsRequest; + elasticDslContext.getParseResult().setFieldMappingsRequest((GetFieldMappingsRequest) mappingsRequest); + elasticDslContext.getParseResult().setIndices(Arrays.asList(getFieldMappingsRequest.indices())); + }else{ + throw new ElasticSql2DslException("[syntax error] not support desc like this syntax"); + } + return elasticDslContext.getParseResult(); + } case SELECT: default: { ElasticSqlExprParser elasticSqlExprParser = new ElasticSqlExprParser(sql); @@ -54,7 +74,7 @@ public ElasticSqlParseResult parse(String sql) throws ElasticSql2DslException { sqlParser.parse(elasticDslContext); } } else { - throw new ElasticSql2DslException("[syntax error] Sql only support Select,Delete Sql"); + throw new ElasticSql2DslException("[syntax error] Sql only support Select,Delete,Desc Sql"); } return elasticDslContext.getParseResult(); } diff --git a/src/main/java/io/github/iamazy/elasticsearch/dsl/sql/parser/query/method/mapping/MappingQueryParser.java b/src/main/java/io/github/iamazy/elasticsearch/dsl/sql/parser/query/method/mapping/MappingQueryParser.java new file mode 100644 index 0000000..03c48d7 --- /dev/null +++ b/src/main/java/io/github/iamazy/elasticsearch/dsl/sql/parser/query/method/mapping/MappingQueryParser.java @@ -0,0 +1,39 @@ +package io.github.iamazy.elasticsearch.dsl.sql.parser.query.method.mapping; + + +import io.github.iamazy.elasticsearch.dsl.sql.exception.ElasticSql2DslException; +import org.apache.commons.lang3.StringUtils; +import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsRequest; +import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest; + +/** + * @author iamazy + * @date 2019/5/5 + * @descrition + **/ +public class MappingQueryParser { + + public static Object parse(String sql) { + String[] descItems = StringUtils.split(sql, " "); + GetFieldMappingsRequest getFieldMappingsRequest = new GetFieldMappingsRequest(); + GetMappingsRequest getMappingsRequest = new GetMappingsRequest(); + if (descItems.length == 2) { + String[] items = descItems[1].split("/"); + switch (items.length) { + case 2: { + getFieldMappingsRequest.indices(items[0]); + getFieldMappingsRequest.fields(items[1]); + return getFieldMappingsRequest; + } + case 1: + default: { + getMappingsRequest.indices(items[0]); + return getMappingsRequest; + } + } + } else { + throw new ElasticSql2DslException("[syntax error] desc must have table name or table/field name"); + } + } + +} diff --git a/src/test/java/io/github/iamazy/elasticsearch/dsl/sql/DescTest.java b/src/test/java/io/github/iamazy/elasticsearch/dsl/sql/DescTest.java new file mode 100644 index 0000000..4f5b9f3 --- /dev/null +++ b/src/test/java/io/github/iamazy/elasticsearch/dsl/sql/DescTest.java @@ -0,0 +1,20 @@ +package io.github.iamazy.elasticsearch.dsl.sql; + +import io.github.iamazy.elasticsearch.dsl.sql.model.ElasticSqlParseResult; +import io.github.iamazy.elasticsearch.dsl.sql.parser.ElasticSql2DslParser; +import org.junit.Test; + +/** + * @author iamazy + * @date 2019/5/5 + * @descrition + **/ +public class DescTest { + + @Test + public void test3(){ + String sql="desc device_info"; + ElasticSql2DslParser sql2DslParser=new ElasticSql2DslParser(); + ElasticSqlParseResult parseResult = sql2DslParser.parse(sql); + } +}