Skip to content

Commit 619bc2d

Browse files
zhongshushi-yuan
authored andcommitted
Merge pull request #793 from LongLonger/elastic6.1.1_zhongshu_dev_01
1 parent f1e076f commit 619bc2d

39 files changed

+1250
-170
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ src/_site/vendor/codemirror/mode/jinja2/.goutputstream-*
2020
src/_site/node_modules
2121
src/site-server/node_modules
2222
*~
23+
.DS_Store

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,7 +637,9 @@ http://localhost:9200/_sql/_explain?sql=select * from indexName limit 10
637637
* SQL Select
638638
* SQL Delete
639639
* SQL Where
640+
* can use "case when" in where clause
640641
* SQL Order By
642+
* can use "case when" in order by clause
641643
* SQL Group By
642644
* SQL AND & OR
643645
* SQL Like
@@ -663,9 +665,20 @@ http://localhost:9200/_sql/_explain?sql=select * from indexName limit 10
663665
* SQL log10
664666
* SQL substring
665667
* SQL round
668+
* eg: round(10.135, 2) --> 10.14
666669
* SQL sqrt
667670
* SQL concat_ws
668671
* SQL union and minus
672+
* SQL case when
673+
* can use "in"、"not in" judge in case when clause
674+
* can execute simple calculation in case when clause, eg : case when 1 = 1 then field_1 + field_2 else 0 end
675+
* SQL if
676+
* select if(sex='1','男','女') from t_user;
677+
* SQL limit
678+
* can set aggregation bucket size and shard size by setting limit, shardSize = 20 * bucketSize
679+
* eg: select city,count(*) as user_count from t_user group by city limit 100;
680+
* on the above example, the bucket size is 100, shard size is 20*100 = 2000
681+
669682

670683
## JDBC Support (Experimental feature)
671684

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<modelVersion>4.0.0</modelVersion>
44
<groupId>org.nlpcn</groupId>
55
<artifactId>elasticsearch-sql</artifactId>
6-
<version>6.5.3.0</version>
6+
<version>6.5.3.1</version>
77
<packaging>jar</packaging>
88
<description>Query elasticsearch using SQL</description>
99
<name>elasticsearch-sql</name>

src/_site/controllers.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ function updateWithScrollIfNeeded (query) {
180180
if(selectedQuery != "" && selectedQuery != undefined){
181181
query = selectedQuery;
182182
}
183+
183184
query = updateWithScrollIfNeeded(query);
184185
$http.post($scope.url + "_sql", query)
185186
.success(function(data, status, headers, config) {

src/_site/query.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -222,12 +222,12 @@ var AggregationQueryResultHandler = function(data) {
222222
}
223223
}
224224

225-
else {
225+
else { //zhongshu-comment 没有子bucket了,就是最里面的那一层了
226226
var obj = $.extend({}, additionalColumns)
227227
if(bucketName != undefined) {
228228
if(bucketName != undefined) {
229229
if("key_as_string" in bucket){
230-
obj[bucketName] = bucket["key_as_string"]
230+
obj[bucketName] = bucket["key_as_string"] //zhongshu-comment 给字段取别名
231231
}
232232
else {
233233
obj[bucketName] = bucket.key
@@ -238,7 +238,7 @@ var AggregationQueryResultHandler = function(data) {
238238
for(var field in bucket) {
239239

240240
var bucketValue = bucket[field]
241-
if(bucketValue.buckets != undefined ){
241+
if(bucketValue.buckets != undefined ){ //zhongshu-comment 如果还有子bucket的话,那就继续递归
242242
var newRows = getRows(subBucketName, bucketValue, newAdditionalColumns);
243243
$.merge(rows, newRows);
244244
continue;
@@ -272,7 +272,7 @@ var AggregationQueryResultHandler = function(data) {
272272
return rows
273273
}
274274

275-
275+
//zhongshu-comment 递归
276276
function fillFieldsForSpecificAggregation(obj,value,field)
277277
{
278278

@@ -287,6 +287,7 @@ var AggregationQueryResultHandler = function(data) {
287287
return;
288288
}
289289

290+
//zhongshu-comment 递归
290291
function getSubBuckets(bucket) {
291292
var subBuckets = [];
292293
for(var field in bucket) {
@@ -297,7 +298,7 @@ var AggregationQueryResultHandler = function(data) {
297298
}
298299
}
299300
else {
300-
innerAgg = bucket[field];
301+
innerAgg = bucket[field]; //zhongshu-comment innerAgg这个变量是哪来的,貌似没声明,到时问问松哥
301302
for(var innerField in innerAgg){
302303
if(typeof(innerAgg[innerField])=="object"){
303304
innerBuckets = getSubBuckets(innerAgg[innerField]);
@@ -312,7 +313,7 @@ var AggregationQueryResultHandler = function(data) {
312313

313314

314315
this.data = data
315-
this.flattenBuckets = getRows(undefined, data.aggregations, {})
316+
this.flattenBuckets = getRows(undefined, data.aggregations, {}) //zhongshu-comment 入口
316317
};
317318

318319
AggregationQueryResultHandler.prototype.getHead = function() {

src/main/java/org/elasticsearch/plugin/nlpcn/RestSqlAction.java

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -49,28 +49,34 @@ protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient cli
4949
sql = request.content().utf8ToString();
5050
}
5151
try {
52-
SearchDao searchDao = new SearchDao(client);
53-
QueryAction queryAction= null;
52+
SearchDao searchDao = new SearchDao(client);
53+
QueryAction queryAction = null;
5454

55-
queryAction = searchDao.explain(sql);
55+
queryAction = searchDao.explain(sql);//zhongshu-comment 语法解析,将sql字符串解析为一个Java查询对象
5656

57-
// TODO add unittests to explain. (rest level?)
58-
if (request.path().endsWith("/_explain")) {
59-
final String jsonExplanation = queryAction.explain().explain();
60-
return channel -> channel.sendResponse(new BytesRestResponse(RestStatus.OK, XContentType.JSON.mediaType(), jsonExplanation));
61-
} else {
62-
Map<String, String> params = request.params();
63-
RestExecutor restExecutor = ActionRequestRestExecuterFactory.createExecutor(params.get("format"));
64-
final QueryAction finalQueryAction = queryAction;
65-
//doing this hack because elasticsearch throws exception for un-consumed props
66-
Map<String,String> additionalParams = new HashMap<>();
67-
for (String paramName : responseParams()) {
68-
if (request.hasParam(paramName)) {
69-
additionalParams.put(paramName, request.param(paramName));
57+
// TODO add unit tests to explain. (rest level?)
58+
if (request.path().endsWith("/_explain")) {
59+
final String jsonExplanation = queryAction.explain().explain();
60+
return channel -> channel.sendResponse(new BytesRestResponse(RestStatus.OK, XContentType.JSON.mediaType(), jsonExplanation));
61+
} else {
62+
Map<String, String> params = request.params();
63+
64+
//zhongshu-comment 生成一个负责用rest方式查询es的对象RestExecutor,返回的实现类是:ElasticDefaultRestExecutor
65+
RestExecutor restExecutor = ActionRequestRestExecuterFactory.createExecutor(params.get("format"));
66+
final QueryAction finalQueryAction = queryAction;
67+
//doing this hack because elasticsearch throws exception for un-consumed props
68+
Map<String, String> additionalParams = new HashMap<>();
69+
for (String paramName : responseParams()) {
70+
if (request.hasParam(paramName)) {
71+
additionalParams.put(paramName, request.param(paramName));
72+
}
7073
}
74+
//zhongshu-comment restExecutor.execute()方法里会调用es查询的相关rest api
75+
//zhongshu-comment restExecutor.execute()方法的第1、4个参数是框架传进来的参数,第2、3个参数是可以自己生成的参数,所以要多注重一点
76+
//zhongshu-comment 默认调用的是ElasticDefaultRestExecutor这个子类
77+
//todo 这是什么语法:搜索java8 -> lambda表达式:https://blog.csdn.net/ioriogami/article/details/12782141
78+
return channel -> restExecutor.execute(client, additionalParams, finalQueryAction, channel);
7179
}
72-
return channel -> restExecutor.execute(client,additionalParams, finalQueryAction,channel);
73-
}
7480
} catch (SqlParseException | SQLFeatureNotSupportedException e) {
7581
e.printStackTrace();
7682
}

src/main/java/org/elasticsearch/plugin/nlpcn/executors/ElasticDefaultRestExecutor.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,25 +33,37 @@ public ElasticDefaultRestExecutor() {
3333

3434
/**
3535
* Execute the ActionRequest and returns the REST response using the channel.
36+
* zhongshu-comment 第二个参数Map<String, String> params 并没有被使用
3637
*/
3738
@Override
3839
public void execute(Client client, Map<String, String> params, QueryAction queryAction, RestChannel channel) throws Exception {
40+
//zhongshu-comment queryAction的使命结束了,交由SqlElasticRequestBuilder接力,SqlElasticRequestBuilder是es-sql自己定义的一个类,不是es原生api
3941
SqlElasticRequestBuilder requestBuilder = queryAction.explain();
42+
43+
//zhongshu-comment 看这行,将QueryAction对象转为es查询对象,这个是重点了,到这步就已经成功将sql字符串转化为es查询请求了
44+
//zhongshu-comment ActionRequest是es的原生api
4045
ActionRequest request = requestBuilder.request();
4146

42-
if (requestBuilder instanceof JoinRequestBuilder) {
47+
//zhongshu-comment 应该是分别对应6中QueryAction子类实现
48+
if (requestBuilder instanceof JoinRequestBuilder) { //zhongshu-comment 对应连接查询:ESJoinQueryAction
4349
ElasticJoinExecutor executor = ElasticJoinExecutor.createJoinExecutor(client, requestBuilder);
4450
executor.run();
4551
executor.sendResponse(channel);
46-
} else if (requestBuilder instanceof MultiQueryRequestBuilder) {
52+
} else if (requestBuilder instanceof MultiQueryRequestBuilder) { //zhongshu-comment 对应union查询:MultiQueryAction
4753
ElasticHitsExecutor executor = MultiRequestExecutorFactory.createExecutor(client, (MultiQueryRequestBuilder) requestBuilder);
4854
executor.run();
4955
sendDefaultResponse(executor.getHits(), channel);
5056
} else if (request instanceof SearchRequest) {
57+
//zhongshu-comment 对应的QueryAction实现子类:DefaultQueryAction、AggregationQueryAction
58+
//zhongshu-comment 对应的SqlElasticRequestBuilder实现子类:SqlElasticSearchRequestBuilder
5159
client.search((SearchRequest) request, new RestStatusToXContentListener<>(channel));
5260
} else if (request instanceof DeleteByQueryRequest) {
61+
//zhongshu-comment 对应的QueryAction实现子类:DeleteQueryAction
62+
//zhongshu-comment 对应的SqlElasticRequestBuilder实现子类:SqlElasticDeleteByQueryRequestBuilder
5363
requestBuilder.getBuilder().execute(new BulkIndexByScrollResponseContentListener(channel, Maps.newHashMap()));
5464
} else if (request instanceof GetIndexRequest) {
65+
//zhongshu-comment 对应的QueryAction实现子类:ShowQueryAction
66+
//zhongshu-comment 对应的SqlElasticRequestBuilder实现子类:是一个匿名内部类,跳进去queryAction.explain()看
5567
requestBuilder.getBuilder().execute(new GetIndexRequestRestListener(channel, (GetIndexRequest) request));
5668
} else if (request instanceof SearchScrollRequest) {
5769
client.searchScroll((SearchScrollRequest) request, new RestStatusToXContentListener<>(channel));

src/main/java/org/nlpcn/es4sql/SQLFunctions.java

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,34 @@ public class SQLFunctions {
2525
"random", "abs", //nummber operator
2626
"split", "concat_ws", "substring", "trim",//string operator
2727
"add", "multiply", "divide", "subtract", "modulus",//binary operator
28-
"field", "date_format"
28+
"field", "date_format", "if"
2929
);
3030

3131

3232
public static Tuple<String, String> function(String methodName, List<KVValue> paramers, String name,boolean returnValue) {
3333
Tuple<String, String> functionStr = null;
34-
switch (methodName) {
34+
switch (methodName.toLowerCase()) {
35+
case "if":
36+
String nameIF = "";
37+
String caseString = "";
38+
if(paramers.get(0).value instanceof SQLInListExpr){
39+
nameIF += methodName+"("+((SQLInListExpr) paramers.get(0).value).getExpr()+" in (";
40+
String left = "doc['"+((SQLInListExpr) paramers.get(0).value).getExpr().toString()+"'].value";
41+
List<SQLExpr> targetList = ((SQLInListExpr) paramers.get(0).value).getTargetList();
42+
for(SQLExpr a:targetList){
43+
caseString += left + " == '" + a.toString() + "' ||";
44+
nameIF += a.toString()+",";
45+
}
46+
caseString = caseString.substring(0,caseString.length()-2);
47+
nameIF = nameIF.substring(0,nameIF.length()-1)+"),";
48+
}else{
49+
String left = "doc['"+paramers.get(0).key+"'].value";
50+
caseString += left + " == '" + paramers.get(0).value+"'";
51+
nameIF = methodName+"("+paramers.get(0).toString()+",";
52+
}
53+
nameIF += paramers.get(1).value+","+paramers.get(2).value+")";
54+
functionStr = new Tuple<>(nameIF,"if(("+caseString+")){"+paramers.get(1).value+"} else {"+paramers.get(2).value+"}");
55+
break;
3556
case "split":
3657
if (paramers.size() == 3) {
3758
functionStr = split(Util.expr2Object((SQLExpr) paramers.get(0).value).toString(),
@@ -66,6 +87,12 @@ public static Tuple<String, String> function(String methodName, List<KVValue> pa
6687
case "abs":
6788
case "round":
6889
case "floor":
90+
if (paramers.size() == 2) {
91+
//zhongshu-comment es的round()默认是保留到个位,这里给round()函数加上精确到小数点后第几位的功能
92+
int decimalPrecision = Integer.parseInt(paramers.get(1).value.toString());
93+
functionStr = mathRoundTemplate("Math."+methodName,methodName,Util.expr2Object((SQLExpr) paramers.get(0).value).toString(), name, decimalPrecision);
94+
break;
95+
}
6996
case "ceil":
7097
case "cbrt":
7198
case "rint":
@@ -131,7 +158,7 @@ public static Tuple<String, String> function(String methodName, List<KVValue> pa
131158
default:
132159

133160
}
134-
if(returnValue){
161+
if(returnValue && !methodName.equalsIgnoreCase("if")){
135162
String generatedFieldName = functionStr.v1();
136163
String returnCommand = ";return " + generatedFieldName +";" ;
137164
String newScript = functionStr.v2() + returnCommand;
@@ -328,6 +355,23 @@ private static Tuple<String, String> mathSingleValueTemplate(String methodName,
328355

329356
}
330357

358+
private static Tuple<String, String> mathRoundTemplate(String methodName, String fieldName, String strColumn, String valueName, int decimalPrecision) {
359+
360+
StringBuilder sb = new StringBuilder("1");
361+
for (int i = 0; i < decimalPrecision; i++) {
362+
sb.append("0");
363+
}
364+
double num = Double.parseDouble(sb.toString());
365+
366+
String name = fieldName + "_" + random();
367+
if (valueName == null) {
368+
return new Tuple<>(name, "def " + name + " = " + methodName + "((doc['" + strColumn + "'].value) * " + num + ")/" + num);
369+
} else {
370+
return new Tuple<>(name, strColumn + ";def " + name + " = " + methodName + "((" + valueName + ") * " + num + ")/" + num);
371+
}
372+
373+
}
374+
331375
public static Tuple<String, String> strSingleValueTemplate(String methodName, String strColumn, String valueName) {
332376
String name = methodName + "_" + random();
333377
if (valueName == null) {

src/main/java/org/nlpcn/es4sql/Util.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,14 @@ public static Object getScriptValueWithQuote(SQLExpr expr, String quote) throws
101101
return ((SQLNumericLiteralExpr) expr).getNumber();
102102
} else if (expr instanceof SQLNullExpr) {
103103
return ((SQLNullExpr) expr).toString().toLowerCase();
104-
}
105-
throw new SqlParseException("could not parse sqlBinaryOpExpr need to be identifier/valuable got" + expr.getClass().toString() + " with value:" + expr.toString());
104+
} else if (expr instanceof SQLBinaryOpExpr) {
105+
//zhongshu-comment 该分支由忠树添加
106+
String left = "doc['" + ((SQLBinaryOpExpr) expr).getLeft().toString() + "'].value";
107+
String operator = ((SQLBinaryOpExpr) expr).getOperator().getName();
108+
String right = "doc['" + ((SQLBinaryOpExpr) expr).getRight().toString() + "'].value";
109+
return left + operator + right;
110+
}
111+
throw new SqlParseException("could not parse sqlBinaryOpExpr need to be identifier/valuable got " + expr.getClass().toString() + " with value:" + expr.toString());
106112
}
107113

108114
public static boolean isFromJoinOrUnionTable(SQLExpr expr) {
@@ -139,7 +145,7 @@ public static double[] KV2DoubleArr(List<KVValue> params) {
139145
double[] ds = new double[params.size()];
140146
int i = 0;
141147
for (KVValue v : params) {
142-
ds[i] = Double.parseDouble(v.value.toString());
148+
ds[i] = ((Number) v.value).doubleValue();
143149
i++;
144150
}
145151
return ds;

src/main/java/org/nlpcn/es4sql/domain/Condition.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ public SQLExpr getValueExpr() {
8989
private boolean isChildren;
9090
private String childType;
9191

92+
public Condition(CONN conn) {
93+
super(conn);
94+
}
95+
9296
public Condition(CONN conn, String field, SQLExpr nameExpr, String condition, Object obj, SQLExpr valueExpr) throws SqlParseException {
9397
this(conn, field, nameExpr, condition, obj, valueExpr, null);
9498
}

0 commit comments

Comments
 (0)