You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@metamodel.apache.org by ar...@apache.org on 2021/02/17 08:11:24 UTC

[metamodel] 03/05: MM-1233: Refactoring, DIFFERENT_FROM operator.

This is an automated email from the ASF dual-hosted git repository.

arjansh pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/metamodel.git

commit 142c4ae09f55af87fd15a66af78c887a663e4252
Author: jakub <j....@quadient.com>
AuthorDate: Mon Feb 15 13:43:20 2021 +0100

    MM-1233: Refactoring, DIFFERENT_FROM operator.
---
 .../elasticsearch/common/ElasticSearchUtils.java   | 118 ++++++++++++---------
 .../common/ElasticSearchUtilsTest.java             |  27 ++++-
 2 files changed, 92 insertions(+), 53 deletions(-)

diff --git a/elasticsearch/common/src/main/java/org/apache/metamodel/elasticsearch/common/ElasticSearchUtils.java b/elasticsearch/common/src/main/java/org/apache/metamodel/elasticsearch/common/ElasticSearchUtils.java
index 5458174..d051c32 100644
--- a/elasticsearch/common/src/main/java/org/apache/metamodel/elasticsearch/common/ElasticSearchUtils.java
+++ b/elasticsearch/common/src/main/java/org/apache/metamodel/elasticsearch/common/ElasticSearchUtils.java
@@ -170,63 +170,18 @@ public class ElasticSearchUtils {
      * @return a {@link QueryBuilder} if one was produced, or null if the items
      *         could not be pushed down to an ElasticSearch query
      */
-    public static QueryBuilder createQueryBuilderForSimpleWhere(List<FilterItem> whereItems,
-            LogicalOperator logicalOperator) {
+    public static QueryBuilder createQueryBuilderForSimpleWhere(final List<FilterItem> whereItems,
+            final LogicalOperator logicalOperator) {
         if (whereItems.isEmpty()) {
             return QueryBuilders.matchAllQuery();
         }
 
-        List<QueryBuilder> children = new ArrayList<>(whereItems.size());
-        for (FilterItem item : whereItems) {
-            final QueryBuilder itemQueryBuilder;
-
-            if (item.isCompoundFilter()) {
-                final List<FilterItem> childItems = Arrays.asList(item.getChildItems());
-                itemQueryBuilder = createQueryBuilderForSimpleWhere(childItems, item.getLogicalOperator());
-                if (itemQueryBuilder == null) {
-                    // something was not supported, so we have to forfeit here
-                    // too.
-                    return null;
-                }
-            } else {
-                final Column column = item.getSelectItem().getColumn();
-                if (column == null) {
-                    // unsupported type of where item - must have a column
-                    // reference
-                    return null;
-                }
-                final String fieldName = column.getName();
-                final Object operand = item.getOperand();
-                final OperatorType operator = item.getOperator();
-
-                if (OperatorType.EQUALS_TO.equals(operator)) {
-                    if (operand == null) {
-                        itemQueryBuilder = getMissingQuery(fieldName);
-                    } else if (column.getType().isLiteral()) {
-                        itemQueryBuilder = QueryBuilders.matchQuery(fieldName, operand);
-                    } else {
-                        itemQueryBuilder = QueryBuilders.termQuery(fieldName, operand);
-                    }
-                } else if (OperatorType.DIFFERENT_FROM.equals(operator)) {
-                    if (operand == null) {
-                        itemQueryBuilder = getExistsQuery(fieldName);
-                    } else {
-                        itemQueryBuilder = QueryBuilders.boolQuery().mustNot(QueryBuilders.termQuery(fieldName,
-                                operand));
-                    }
-                } else if (OperatorType.IN.equals(operator)) {
-                    final List<?> operands = CollectionUtils.toList(operand);
-                    if (column.getType().isLiteral()) {
-                        itemQueryBuilder = QueryBuilders.termQuery(fieldName, operand);
-                    } else {
-                        itemQueryBuilder = QueryBuilders.termsQuery(fieldName, operands);
-                    }
-                } else {
-                    // not (yet) support operator types
-                    return null;
-                }
+        final List<QueryBuilder> children = new ArrayList<>(whereItems.size());
+        for (final FilterItem item : whereItems) {
+            final QueryBuilder itemQueryBuilder = createFilterItemQueryBuilder(item);
+            if (itemQueryBuilder == null) {
+                return null;
             }
-
             children.add(itemQueryBuilder);
         }
 
@@ -249,6 +204,65 @@ public class ElasticSearchUtils {
         return result;
     }
 
+    private static QueryBuilder createFilterItemQueryBuilder(final FilterItem filterItem) {
+        final QueryBuilder itemQueryBuilder;
+        if (filterItem.isCompoundFilter()) {
+            final List<FilterItem> childItems = Arrays.asList(filterItem.getChildItems());
+            itemQueryBuilder = createQueryBuilderForSimpleWhere(childItems, filterItem.getLogicalOperator());
+        } else {
+            final Column column = filterItem.getSelectItem().getColumn();
+            if (column == null) {
+                // unsupported type of where item - must have a column reference
+                return null;
+            }
+            itemQueryBuilder = createQueryBuilderForOperator(filterItem, column);
+        }
+
+        return itemQueryBuilder;
+    }
+
+    private static QueryBuilder createQueryBuilderForOperator(final FilterItem filterItem, final Column column) {
+        if (OperatorType.EQUALS_TO.equals(filterItem.getOperator())) {
+            if (filterItem.getOperand() == null) {
+                return getMissingQuery(column.getName());
+            } else {
+                return matchOrTermQuery(column, filterItem.getOperand());
+            }
+        } else if (OperatorType.DIFFERENT_FROM.equals(filterItem.getOperator())) {
+            if (filterItem.getOperand() == null) {
+                return getExistsQuery(column.getName());
+            } else {
+                return QueryBuilders.boolQuery().mustNot(matchOrTermQuery(column, filterItem.getOperand()));
+            }
+        } else if (OperatorType.IN.equals(filterItem.getOperator())) {
+            final List<?> operands = CollectionUtils.toList(filterItem.getOperand());
+            if (column.getType().isLiteral()) {
+                return createMultipleValuesQueryBuilder(column.getName(), operands);
+            } else {
+                return QueryBuilders.termsQuery(column.getName(), operands);
+            }
+        } else {
+            // not (yet) supported operator types
+            return null;
+        }
+    }
+
+    private static QueryBuilder matchOrTermQuery(final Column column, final Object operand) {
+        if (column.getType().isLiteral()) {
+            return QueryBuilders.matchQuery(column.getName(), operand);
+        } else {
+            return QueryBuilders.termQuery(column.getName(), operand);
+        }
+    }
+
+    private static QueryBuilder createMultipleValuesQueryBuilder(final String columnName, final List<?> operands) {
+        final BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
+        for (final Object value : operands) {
+            boolQueryBuilder.should(QueryBuilders.matchQuery(columnName, value.toString()));
+        }
+        return boolQueryBuilder;
+    }
+
     public static ColumnType getColumnTypeFromElasticSearchType(final String metaDataFieldType) {
         final ColumnType columnType;
         if (metaDataFieldType.startsWith("date")) {
diff --git a/elasticsearch/common/src/test/java/org/apache/metamodel/elasticsearch/common/ElasticSearchUtilsTest.java b/elasticsearch/common/src/test/java/org/apache/metamodel/elasticsearch/common/ElasticSearchUtilsTest.java
index 8228316..4d18b27 100644
--- a/elasticsearch/common/src/test/java/org/apache/metamodel/elasticsearch/common/ElasticSearchUtilsTest.java
+++ b/elasticsearch/common/src/test/java/org/apache/metamodel/elasticsearch/common/ElasticSearchUtilsTest.java
@@ -73,11 +73,36 @@ public class ElasticSearchUtilsTest extends TestCase {
     /**
      * For text-based conditions a 'match' query is recommended (instead of 'term' query).
      */
-    public void testMatchQueryIsCreatedForTextFilter() {
+    public void testMatchQueryIsCreatedForTextEqualTo() {
         final SelectItem selectItem = new SelectItem(new MutableColumn("column_name", ColumnType.STRING));
         final FilterItem filterItem = new FilterItem(selectItem, OperatorType.EQUALS_TO, "text-value");
         final QueryBuilder queryBuilder =
                 ElasticSearchUtils.createQueryBuilderForSimpleWhere(Collections.singletonList(filterItem), null);
         assertEquals("match", queryBuilder.getName());
     }
+
+    /**
+     * For text-based conditions a 'match' query is recommended (instead of 'term' query).
+     * In case of 'DIFFERENT_FROM', we need a 'bool' query with 'must not' and 'match' query.
+     */
+    public void testBoolQueryIsCreatedForTextDifferentFrom() {
+        final SelectItem selectItem = new SelectItem(new MutableColumn("column_name", ColumnType.STRING));
+        final FilterItem filterItem = new FilterItem(selectItem, OperatorType.DIFFERENT_FROM, "text-value");
+        final QueryBuilder queryBuilder =
+                ElasticSearchUtils.createQueryBuilderForSimpleWhere(Collections.singletonList(filterItem), null);
+        assertEquals("bool", queryBuilder.getName());
+    }
+
+    /**
+     * For text-based conditions a 'match' query is recommended (instead of 'term' query).
+     * To simulate 'IN' operator, we need a 'bool' query with multiple 'match' queries combined with 'OR'.
+     */
+    public void testBoolQueryIsCreatedForTextIn() {
+        final SelectItem selectItem = new SelectItem(new MutableColumn("column_name", ColumnType.STRING));
+        final FilterItem filterItem =
+                new FilterItem(selectItem, OperatorType.IN, Arrays.asList("text-value-a", "text-value-b"));
+        final QueryBuilder queryBuilder =
+                ElasticSearchUtils.createQueryBuilderForSimpleWhere(Collections.singletonList(filterItem), null);
+        assertEquals("bool", queryBuilder.getName());
+    }
 }