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);
+ }
+}