QueryWhereConditionParser.java 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. package org.elasticsearch.dsl.parser.syntax;
  2. import com.alibaba.druid.sql.ast.SQLExpr;
  3. import com.alibaba.druid.sql.ast.expr.*;
  4. import com.google.common.collect.ArrayListMultimap;
  5. import com.google.common.collect.ListMultimap;
  6. import com.google.common.collect.Lists;
  7. import org.apache.commons.collections.CollectionUtils;
  8. import org.elasticsearch.dsl.bean.AtomFilter;
  9. import org.elasticsearch.dsl.bean.ElasticDslContext;
  10. import org.elasticsearch.dsl.bean.ElasticSqlQueryField;
  11. import org.elasticsearch.dsl.bean.SQLCondition;
  12. import org.elasticsearch.dsl.enums.QueryFieldType;
  13. import org.elasticsearch.dsl.enums.SQLBoolOperator;
  14. import org.elasticsearch.dsl.enums.SQLConditionOperator;
  15. import org.elasticsearch.dsl.enums.SQLConditionType;
  16. import org.elasticsearch.dsl.exception.ElasticSql2DslException;
  17. import org.elasticsearch.dsl.parser.QueryParser;
  18. import org.elasticsearch.dsl.parser.helper.ElasticSqlArgTransferHelper;
  19. import org.elasticsearch.dsl.parser.listener.ParseActionListener;
  20. import org.elasticsearch.index.query.BoolFilterBuilder;
  21. import org.elasticsearch.index.query.FilterBuilder;
  22. import org.elasticsearch.index.query.FilterBuilders;
  23. import org.elasticsearch.sql.ElasticSqlSelectQueryBlock;
  24. import java.util.List;
  25. public class QueryWhereConditionParser implements QueryParser {
  26. private ParseActionListener parseActionListener;
  27. public QueryWhereConditionParser(ParseActionListener parseActionListener) {
  28. this.parseActionListener = parseActionListener;
  29. }
  30. @Override
  31. public void parse(ElasticDslContext dslContext) {
  32. ElasticSqlSelectQueryBlock queryBlock = (ElasticSqlSelectQueryBlock) dslContext.getQueryExpr().getSubQuery().getQuery();
  33. if (queryBlock.getWhere() != null) {
  34. SQLCondition whereCondition = parseFilterCondition(dslContext, queryBlock.getWhere());
  35. SQLBoolOperator operator = whereCondition.getOperator();
  36. if(SQLConditionType.Atom == whereCondition.getSQLConditionType()) {
  37. operator = SQLBoolOperator.AND;
  38. }
  39. BoolFilterBuilder boolFilter = mergeAtomFilter(whereCondition.getFilterList(), operator);
  40. dslContext.getParseResult().setWhereCondition(boolFilter);
  41. }
  42. }
  43. private SQLCondition parseFilterCondition(ElasticDslContext dslContext, SQLExpr sqlExpr) {
  44. if (sqlExpr instanceof SQLBinaryOpExpr) {
  45. SQLBinaryOpExpr sqlBinOpExpr = (SQLBinaryOpExpr) sqlExpr;
  46. SQLBinaryOperator binaryOperator = sqlBinOpExpr.getOperator();
  47. if (SQLBinaryOperator.BooleanAnd == binaryOperator || SQLBinaryOperator.BooleanOr == binaryOperator) {
  48. SQLBoolOperator operator = SQLBinaryOperator.BooleanAnd == binaryOperator ? SQLBoolOperator.AND : SQLBoolOperator.OR;
  49. SQLCondition leftCondition = parseFilterCondition(dslContext, sqlBinOpExpr.getLeft());
  50. SQLCondition rightCondition = parseFilterCondition(dslContext, sqlBinOpExpr.getRight());
  51. List<AtomFilter> curFilterList = Lists.newArrayList();
  52. combineFilterBuilder(curFilterList, leftCondition, operator);
  53. combineFilterBuilder(curFilterList, rightCondition, operator);
  54. return new SQLCondition(curFilterList, operator);
  55. }
  56. }
  57. return new SQLCondition(parseAtomFilterCondition(dslContext, sqlExpr), SQLConditionType.Atom);
  58. }
  59. private void combineFilterBuilder(List<AtomFilter> combiner, SQLCondition sqlCondition, SQLBoolOperator binOperator) {
  60. if (SQLConditionType.Atom == sqlCondition.getSQLConditionType() || sqlCondition.getOperator() == binOperator) {
  61. combiner.addAll(sqlCondition.getFilterList());
  62. }
  63. else {
  64. //todo binOperator -> sqlCondition.getOperator()
  65. BoolFilterBuilder subBoolFilter = mergeAtomFilter(sqlCondition.getFilterList(), sqlCondition.getOperator());
  66. combiner.add(new AtomFilter(subBoolFilter));
  67. }
  68. }
  69. private BoolFilterBuilder mergeAtomFilter(List<AtomFilter> atomFilterList, SQLBoolOperator operator) {
  70. BoolFilterBuilder subBoolFilter = FilterBuilders.boolFilter();
  71. ListMultimap<String, FilterBuilder> listMultiMap = ArrayListMultimap.create();
  72. for (AtomFilter atomFilter : atomFilterList) {
  73. if(Boolean.FALSE == atomFilter.getNestedFilter()) {
  74. if (operator == SQLBoolOperator.AND) {
  75. subBoolFilter.must(atomFilter.getFilter());
  76. }
  77. if (operator == SQLBoolOperator.OR) {
  78. subBoolFilter.should(atomFilter.getFilter());
  79. }
  80. }
  81. else {
  82. String nestedDocPrefix = atomFilter.getNestedFilterPathContext();
  83. listMultiMap.put(nestedDocPrefix, atomFilter.getFilter());
  84. }
  85. }
  86. for (String nestedDocPrefix : listMultiMap.keySet()) {
  87. List<FilterBuilder> nestedFilterList = listMultiMap.get(nestedDocPrefix);
  88. if(nestedFilterList.size() == 1) {
  89. if (operator == SQLBoolOperator.AND) {
  90. subBoolFilter.must(FilterBuilders.nestedFilter(nestedDocPrefix, nestedFilterList.get(0)));
  91. }
  92. if (operator == SQLBoolOperator.OR) {
  93. subBoolFilter.should(FilterBuilders.nestedFilter(nestedDocPrefix, nestedFilterList.get(0)));
  94. }
  95. continue;
  96. }
  97. BoolFilterBuilder boolNestedFilter = FilterBuilders.boolFilter();
  98. for (FilterBuilder nestedFilterItem : nestedFilterList) {
  99. if (operator == SQLBoolOperator.AND) {
  100. boolNestedFilter.must(nestedFilterItem);
  101. }
  102. if (operator == SQLBoolOperator.OR) {
  103. boolNestedFilter.should(nestedFilterItem);
  104. }
  105. }
  106. if (operator == SQLBoolOperator.AND) {
  107. subBoolFilter.must(FilterBuilders.nestedFilter(nestedDocPrefix, boolNestedFilter));
  108. }
  109. if (operator == SQLBoolOperator.OR) {
  110. subBoolFilter.should(FilterBuilders.nestedFilter(nestedDocPrefix, boolNestedFilter));
  111. }
  112. }
  113. return subBoolFilter;
  114. }
  115. private AtomFilter parseAtomFilterCondition(ElasticDslContext dslContext, SQLExpr sqlExpr) {
  116. if (sqlExpr instanceof SQLBinaryOpExpr) {
  117. SQLBinaryOpExpr sqlBinOpExpr = (SQLBinaryOpExpr) sqlExpr;
  118. final SQLBinaryOperator binaryOperator = sqlBinOpExpr.getOperator();
  119. if (isValidBinOperator(binaryOperator)) {
  120. //EQ NEQ
  121. if (SQLBinaryOperator.Equality == binaryOperator || SQLBinaryOperator.LessThanOrGreater == binaryOperator || SQLBinaryOperator.NotEqual == binaryOperator) {
  122. Object targetVal = ElasticSqlArgTransferHelper.transferSqlArg(sqlBinOpExpr.getRight(), dslContext.getSqlArgs());
  123. SQLConditionOperator operator = SQLBinaryOperator.Equality == binaryOperator ? SQLConditionOperator.Equality : SQLConditionOperator.NotEqual;
  124. return parseCondition(sqlBinOpExpr.getLeft(), operator, new Object[]{targetVal}, dslContext.getParseResult().getQueryAs(), new ConditionFilterBuilder() {
  125. @Override
  126. public FilterBuilder buildFilter(String leftIdfName, SQLConditionOperator operator, Object[] rightParamValues) {
  127. FilterBuilder eqFilter = FilterBuilders.termFilter(leftIdfName, rightParamValues[0]);
  128. if (SQLConditionOperator.Equality == operator) {
  129. return eqFilter;
  130. } else {
  131. return FilterBuilders.notFilter(eqFilter);
  132. }
  133. }
  134. });
  135. }
  136. //GT GTE LT LTE
  137. if (SQLBinaryOperator.GreaterThan == binaryOperator || SQLBinaryOperator.GreaterThanOrEqual == binaryOperator
  138. || SQLBinaryOperator.LessThan == binaryOperator || SQLBinaryOperator.LessThanOrEqual == binaryOperator) {
  139. SQLConditionOperator operator = null;
  140. if (SQLBinaryOperator.GreaterThan == binaryOperator) {
  141. operator = SQLConditionOperator.GreaterThan;
  142. } else if (SQLBinaryOperator.GreaterThanOrEqual == binaryOperator) {
  143. operator = SQLConditionOperator.GreaterThanOrEqual;
  144. } else if (SQLBinaryOperator.LessThan == binaryOperator) {
  145. operator = SQLConditionOperator.LessThan;
  146. } else if (SQLBinaryOperator.LessThanOrEqual == binaryOperator) {
  147. operator = SQLConditionOperator.LessThanOrEqual;
  148. }
  149. Object targetVal = ElasticSqlArgTransferHelper.transferSqlArg(sqlBinOpExpr.getRight(), dslContext.getSqlArgs());
  150. return parseCondition(sqlBinOpExpr.getLeft(), operator, new Object[]{targetVal}, dslContext.getParseResult().getQueryAs(), new ConditionFilterBuilder() {
  151. @Override
  152. public FilterBuilder buildFilter(String leftIdfName, SQLConditionOperator operator, Object[] rightParamValues) {
  153. FilterBuilder rangeFilter = null;
  154. if (SQLConditionOperator.GreaterThan == operator) {
  155. rangeFilter = FilterBuilders.rangeFilter(leftIdfName).gt(rightParamValues[0]);
  156. } else if (SQLConditionOperator.GreaterThanOrEqual == operator) {
  157. rangeFilter = FilterBuilders.rangeFilter(leftIdfName).gte(rightParamValues[0]);
  158. } else if (SQLConditionOperator.LessThan == operator) {
  159. rangeFilter = FilterBuilders.rangeFilter(leftIdfName).lt(rightParamValues[0]);
  160. } else if (SQLConditionOperator.LessThanOrEqual == operator) {
  161. rangeFilter = FilterBuilders.rangeFilter(leftIdfName).lte(rightParamValues[0]);
  162. }
  163. return rangeFilter;
  164. }
  165. });
  166. }
  167. //IS / IS NOT
  168. if (SQLBinaryOperator.Is == binaryOperator || SQLBinaryOperator.IsNot == binaryOperator) {
  169. if (!(sqlBinOpExpr.getRight() instanceof SQLNullExpr)) {
  170. throw new ElasticSql2DslException("[syntax error] Is/IsNot expr right part should be null");
  171. }
  172. SQLConditionOperator operator = SQLBinaryOperator.Is == binaryOperator ? SQLConditionOperator.IsNull : SQLConditionOperator.IsNotNull;
  173. return parseCondition(sqlBinOpExpr.getLeft(), operator, null, dslContext.getParseResult().getQueryAs(), new ConditionFilterBuilder() {
  174. @Override
  175. public FilterBuilder buildFilter(String leftIdfName, SQLConditionOperator operator, Object[] rightParamValues) {
  176. FilterBuilder missingFilter = FilterBuilders.missingFilter(leftIdfName);
  177. if (SQLConditionOperator.IsNotNull == operator) {
  178. return FilterBuilders.notFilter(missingFilter);
  179. }
  180. return missingFilter;
  181. }
  182. });
  183. }
  184. }
  185. } else if (sqlExpr instanceof SQLInListExpr) {
  186. SQLInListExpr inListExpr = (SQLInListExpr) sqlExpr;
  187. if (CollectionUtils.isEmpty(inListExpr.getTargetList())) {
  188. throw new ElasticSql2DslException("[syntax error] In list expr target list cannot be blank");
  189. }
  190. Object[] targetInList = ElasticSqlArgTransferHelper.transferSqlArgs(inListExpr.getTargetList(), dslContext.getSqlArgs());
  191. SQLConditionOperator operator = inListExpr.isNot() ? SQLConditionOperator.NotIn : SQLConditionOperator.In;
  192. return parseCondition(inListExpr.getExpr(), operator, targetInList, dslContext.getParseResult().getQueryAs(), new ConditionFilterBuilder() {
  193. @Override
  194. public FilterBuilder buildFilter(String leftIdfName, SQLConditionOperator operator, Object[] rightParamValues) {
  195. if (SQLConditionOperator.NotIn == operator) {
  196. return FilterBuilders.notFilter(FilterBuilders.inFilter(leftIdfName, rightParamValues));
  197. } else {
  198. return FilterBuilders.inFilter(leftIdfName, rightParamValues);
  199. }
  200. }
  201. });
  202. } else if (sqlExpr instanceof SQLBetweenExpr) {
  203. SQLBetweenExpr betweenExpr = (SQLBetweenExpr) sqlExpr;
  204. Object from = ElasticSqlArgTransferHelper.transferSqlArg(betweenExpr.getBeginExpr(), dslContext.getSqlArgs());
  205. Object to = ElasticSqlArgTransferHelper.transferSqlArg(betweenExpr.getEndExpr(), dslContext.getSqlArgs());
  206. if (from == null || to == null) {
  207. throw new ElasticSql2DslException("[syntax error] Between Expr only support one of [number,date] arg type");
  208. }
  209. return parseCondition(betweenExpr.getTestExpr(), SQLConditionOperator.BetweenAnd, new Object[]{from, to}, dslContext.getParseResult().getQueryAs(), new ConditionFilterBuilder() {
  210. @Override
  211. public FilterBuilder buildFilter(String leftIdfName, SQLConditionOperator operator, Object[] rightParamValues) {
  212. return FilterBuilders.rangeFilter(leftIdfName).gte(rightParamValues[0]).lte(rightParamValues[1]);
  213. }
  214. });
  215. }
  216. throw new ElasticSql2DslException("[syntax error] Can not support syntax type: " + sqlExpr.toString());
  217. }
  218. private AtomFilter parseCondition(SQLExpr leftQueryFieldExpr, SQLConditionOperator operator, Object[] rightParamValues, String queryAs, ConditionFilterBuilder filterBuilder) {
  219. QueryFieldParser queryFieldParser = new QueryFieldParser();
  220. ElasticSqlQueryField queryField = queryFieldParser.parseConditionQueryField(leftQueryFieldExpr, queryAs);
  221. AtomFilter atomFilter = null;
  222. if (queryField.getQueryFieldType() == QueryFieldType.RootDocField || queryField.getQueryFieldType() == QueryFieldType.InnerDocField) {
  223. FilterBuilder originalFilter = filterBuilder.buildFilter(queryField.getQueryFieldFullName(), operator, rightParamValues);
  224. atomFilter = new AtomFilter(originalFilter);
  225. }
  226. if (queryField.getQueryFieldType() == QueryFieldType.NestedDocField) {
  227. FilterBuilder originalFilter = filterBuilder.buildFilter(queryField.getQueryFieldFullName(), operator, rightParamValues);
  228. atomFilter = new AtomFilter(originalFilter, queryField.getNestedDocContextPath());
  229. }
  230. if (atomFilter == null) {
  231. throw new ElasticSql2DslException(String.format("[syntax error] where condition field can not support type[%s]", queryField.getQueryFieldType()));
  232. }
  233. onAtomConditionParse(queryField, rightParamValues, operator);
  234. return atomFilter;
  235. }
  236. private void onAtomConditionParse(ElasticSqlQueryField paramName, Object[] paramValues, SQLConditionOperator operator) {
  237. try {
  238. parseActionListener.onAtomConditionParse(paramName, paramValues, operator);
  239. } catch (Exception ex) {
  240. try {
  241. parseActionListener.onFailure(ex);
  242. } catch (Exception exp) {
  243. //ignore;
  244. }
  245. }
  246. }
  247. @FunctionalInterface
  248. private interface ConditionFilterBuilder {
  249. FilterBuilder buildFilter(String leftIdfName, SQLConditionOperator operator, Object[] rightParamValues);
  250. }
  251. public boolean isValidBinOperator(SQLBinaryOperator binaryOperator) {
  252. return binaryOperator == SQLBinaryOperator.Equality
  253. || binaryOperator == SQLBinaryOperator.NotEqual
  254. || binaryOperator == SQLBinaryOperator.LessThanOrGreater
  255. || binaryOperator == SQLBinaryOperator.GreaterThan
  256. || binaryOperator == SQLBinaryOperator.GreaterThanOrEqual
  257. || binaryOperator == SQLBinaryOperator.LessThan
  258. || binaryOperator == SQLBinaryOperator.LessThanOrEqual
  259. || binaryOperator == SQLBinaryOperator.Is
  260. || binaryOperator == SQLBinaryOperator.IsNot;
  261. }
  262. }