You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@atlas.apache.org by ma...@apache.org on 2020/10/08 03:18:06 UTC

[atlas] branch master updated: ATLAS-3983: solr index query escape character handling

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 8bb3e85  ATLAS-3983: solr index query escape character handling
8bb3e85 is described below

commit 8bb3e853ea128e1eb2b181e8db869bf7d8050181
Author: Madhan Neethiraj <ma...@apache.org>
AuthorDate: Sun Oct 4 23:51:50 2020 -0700

    ATLAS-3983: solr index query escape character handling
---
 .../apache/atlas/type/AtlasClassificationType.java |   6 +-
 .../org/apache/atlas/type/AtlasEntityType.java     |   6 +-
 .../org/apache/atlas/type/AtlasStructType.java     | 106 +++++++++++++++++++--
 .../atlas/discovery/GraphIndexQueryBuilder.java    |   4 +-
 .../org/apache/atlas/discovery/SearchContext.java  |   4 +-
 .../apache/atlas/discovery/SearchProcessor.java    |  18 ----
 6 files changed, 105 insertions(+), 39 deletions(-)

diff --git a/intg/src/main/java/org/apache/atlas/type/AtlasClassificationType.java b/intg/src/main/java/org/apache/atlas/type/AtlasClassificationType.java
index e0843cb..22259bc 100644
--- a/intg/src/main/java/org/apache/atlas/type/AtlasClassificationType.java
+++ b/intg/src/main/java/org/apache/atlas/type/AtlasClassificationType.java
@@ -65,7 +65,7 @@ public class AtlasClassificationType extends AtlasStructType {
         super(classificationDef);
 
         this.classificationDef = classificationDef;
-        this.typeQryStr        = AtlasAttribute.escapeIndexQueryValue(Collections.singleton(getTypeName()));
+        this.typeQryStr        = AtlasAttribute.escapeIndexQueryValue(Collections.singleton(getTypeName()), true);
     }
 
     /**
@@ -81,7 +81,7 @@ public class AtlasClassificationType extends AtlasStructType {
         super(classificationDef);
 
         this.classificationDef = classificationDef;
-        this.typeQryStr        = AtlasAttribute.escapeIndexQueryValue(Collections.singleton(getTypeName()));
+        this.typeQryStr        = AtlasAttribute.escapeIndexQueryValue(Collections.singleton(getTypeName()), true);
 
         resolveReferences(typeRegistry);
     }
@@ -264,7 +264,7 @@ public class AtlasClassificationType extends AtlasStructType {
 
     public String getTypeAndAllSubTypesQryStr() {
         if (StringUtils.isEmpty(typeAndAllSubTypesQryStr)) {
-            typeAndAllSubTypesQryStr = AtlasAttribute.escapeIndexQueryValue(typeAndAllSubTypes);
+            typeAndAllSubTypesQryStr = AtlasAttribute.escapeIndexQueryValue(typeAndAllSubTypes, true);
         }
 
         return typeAndAllSubTypesQryStr;
diff --git a/intg/src/main/java/org/apache/atlas/type/AtlasEntityType.java b/intg/src/main/java/org/apache/atlas/type/AtlasEntityType.java
index 58de4cc..27c7f73 100644
--- a/intg/src/main/java/org/apache/atlas/type/AtlasEntityType.java
+++ b/intg/src/main/java/org/apache/atlas/type/AtlasEntityType.java
@@ -100,7 +100,7 @@ public class AtlasEntityType extends AtlasStructType {
         super(entityDef);
 
         this.entityDef            = entityDef;
-        this.typeQryStr           = AtlasAttribute.escapeIndexQueryValue(Collections.singleton(getTypeName()));
+        this.typeQryStr           = AtlasAttribute.escapeIndexQueryValue(Collections.singleton(getTypeName()), true);
         this.displayTextAttribute = entityDef.getOption(AtlasEntityDef.OPTION_DISPLAY_TEXT_ATTRIBUTE);
     }
 
@@ -108,7 +108,7 @@ public class AtlasEntityType extends AtlasStructType {
         super(entityDef);
 
         this.entityDef            = entityDef;
-        this.typeQryStr           = AtlasAttribute.escapeIndexQueryValue(Collections.singleton(getTypeName()));
+        this.typeQryStr           = AtlasAttribute.escapeIndexQueryValue(Collections.singleton(getTypeName()), true);
         this.displayTextAttribute = entityDef.getOption(AtlasEntityDef.OPTION_DISPLAY_TEXT_ATTRIBUTE);
 
         resolveReferences(typeRegistry);
@@ -573,7 +573,7 @@ public class AtlasEntityType extends AtlasStructType {
 
     public String getTypeAndAllSubTypesQryStr() {
         if (StringUtils.isEmpty(typeAndAllSubTypesQryStr)) {
-            typeAndAllSubTypesQryStr = AtlasAttribute.escapeIndexQueryValue(typeAndAllSubTypes);
+            typeAndAllSubTypesQryStr = AtlasAttribute.escapeIndexQueryValue(typeAndAllSubTypes, true);
         }
 
         return typeAndAllSubTypesQryStr;
diff --git a/intg/src/main/java/org/apache/atlas/type/AtlasStructType.java b/intg/src/main/java/org/apache/atlas/type/AtlasStructType.java
index b0d88fc..28d2e23 100644
--- a/intg/src/main/java/org/apache/atlas/type/AtlasStructType.java
+++ b/intg/src/main/java/org/apache/atlas/type/AtlasStructType.java
@@ -936,6 +936,10 @@ public class AtlasStructType extends AtlasType {
         }
 
         public static String escapeIndexQueryValue(Collection<String> values) {
+            return escapeIndexQueryValue(values, false);
+        }
+
+        public static String escapeIndexQueryValue(Collection<String> values, boolean allowWildcard) {
             StringBuilder sb = new StringBuilder();
 
             sb.append(BRACE_OPEN_CHAR);
@@ -943,10 +947,10 @@ public class AtlasStructType extends AtlasType {
             if (CollectionUtils.isNotEmpty(values)) {
                 Iterator<String> iter = values.iterator();
 
-                sb.append(escapeIndexQueryValue(iter.next()));
+                sb.append(escapeIndexQueryValue(iter.next(), allowWildcard));
 
                 while (iter.hasNext()) {
-                    sb.append(SPACE_CHAR).append(escapeIndexQueryValue(iter.next()));
+                    sb.append(SPACE_CHAR).append(escapeIndexQueryValue(iter.next(), allowWildcard));
                 }
             }
 
@@ -956,26 +960,109 @@ public class AtlasStructType extends AtlasType {
         }
 
         public static String escapeIndexQueryValue(String value) {
-            String ret = value;
+            return escapeIndexQueryValue(value, false);
+        }
+
+        public static String escapeIndexQueryValue(String value, boolean allowWildcard) {
+            String  ret        = value;
+            boolean quoteValue = false;
+
+            if (hasIndexQueryEscapeChar(value)) {
+                StringBuilder sb = new StringBuilder();
+
+                for (int i = 0; i < value.length(); i++) {
+                    char c = value.charAt(i);
+
+                    if (!(allowWildcard && c == '*') && isIndexQueryEscapeChar(c)) {
+                        sb.append('\\');
+                    }
+
+                    if (!quoteValue) {
+                        quoteValue = shouldQuoteIndexQueryForChar(c);
+                    }
+
+                    sb.append(c);
+                }
+
+                ret = sb.toString();
+            } else if (value != null) {
+                for (int i = 0; i < value.length(); i++) {
+                    if (shouldQuoteIndexQueryForChar(value.charAt(i))) {
+                        quoteValue = true;
+
+                        break;
+                    }
+                }
+            }
 
-            if (StringUtils.containsAny(value, IDX_QRY_OFFENDING_CHARS)) {
-                boolean isQuoteAtStart = value.charAt(0) == DOUBLE_QUOTE_CHAR;
-                boolean isQuoteAtEnd   = value.charAt(value.length() - 1) == DOUBLE_QUOTE_CHAR;
+            if (quoteValue) {
+                boolean isQuoteAtStart = ret.charAt(0) == DOUBLE_QUOTE_CHAR;
+                boolean isQuoteAtEnd   = ret.charAt(ret.length() - 1) == DOUBLE_QUOTE_CHAR;
 
                 if (!isQuoteAtStart) {
                     if (!isQuoteAtEnd) {
-                        ret = DOUBLE_QUOTE_CHAR + value + DOUBLE_QUOTE_CHAR;
+                        ret = DOUBLE_QUOTE_CHAR + ret + DOUBLE_QUOTE_CHAR;
                     } else {
-                        ret = DOUBLE_QUOTE_CHAR + value;
+                        ret = DOUBLE_QUOTE_CHAR + ret;
                     }
                 } else if (!isQuoteAtEnd) {
-                    ret = value + DOUBLE_QUOTE_CHAR;
+                    ret = ret + DOUBLE_QUOTE_CHAR;
                 }
+
             }
 
             return ret;
         }
 
+        private static boolean hasIndexQueryEscapeChar(String value) {
+            if (value != null) {
+                for (int i = 0; i < value.length(); i++) {
+                    if (isIndexQueryEscapeChar(value.charAt(i))) {
+                        return true;
+                    }
+                }
+            }
+
+            return false;
+        }
+
+        private static boolean isIndexQueryEscapeChar(char c) {
+            switch (c) {
+                case '+':
+                case '-':
+                case '&':
+                case '|':
+                case '!':
+                case '(':
+                case ')':
+                case '{':
+                case '}':
+                case '[':
+                case ']':
+                case '^':
+                case '"':
+                case '~':
+                case '*':
+                case '?':
+                case ':':
+                case '\\':
+                case '/':
+                    return true;
+            }
+
+            return false;
+        }
+
+        private static boolean shouldQuoteIndexQueryForChar(char c) {
+            switch (c) {
+                case '@':
+                case ' ':
+                    return true;
+            }
+
+            return false;
+        }
+
         private String getRelationshipEdgeLabel(String relationshipLabel) {
             return (relationshipLabel == null) ? getEdgeLabel(qualifiedName) : relationshipLabel;
         }
@@ -1024,7 +1111,6 @@ public class AtlasStructType extends AtlasType {
                 new String[] {"%", "_p"}, //titan reserved characters
         };
 
-        private static final char[] IDX_QRY_OFFENDING_CHARS = { '@', '/', ' ', '-' };
         private static final char   BRACE_OPEN_CHAR         = '(';
         private static final char   BRACE_CLOSE_CHAR        = ')';
         private static final char   DOUBLE_QUOTE_CHAR       = '"';
diff --git a/repository/src/main/java/org/apache/atlas/discovery/GraphIndexQueryBuilder.java b/repository/src/main/java/org/apache/atlas/discovery/GraphIndexQueryBuilder.java
index 35d64b7..1cd8786 100644
--- a/repository/src/main/java/org/apache/atlas/discovery/GraphIndexQueryBuilder.java
+++ b/repository/src/main/java/org/apache/atlas/discovery/GraphIndexQueryBuilder.java
@@ -17,9 +17,7 @@
  */
 package org.apache.atlas.discovery;
 
-import static org.apache.atlas.discovery.SearchContext.MATCH_ALL_CLASSIFIED;
 import static org.apache.atlas.discovery.SearchContext.MATCH_ALL_NOT_CLASSIFIED;
-import static org.apache.atlas.discovery.SearchContext.MATCH_ALL_WILDCARD_CLASSIFICATION;
 import static org.apache.atlas.discovery.SearchProcessor.INDEX_SEARCH_PREFIX;
 import static org.apache.atlas.repository.Constants.CLASSIFICATION_NAMES_KEY;
 import static org.apache.atlas.repository.Constants.PROPAGATED_CLASSIFICATION_NAMES_KEY;
@@ -39,7 +37,7 @@ public class GraphIndexQueryBuilder {
 
     void addClassificationTypeFilter(StringBuilder indexQuery) {
         if (indexQuery != null && CollectionUtils.isNotEmpty(context.getClassificationNames())) {
-            String classificationNames = AtlasStructType.AtlasAttribute.escapeIndexQueryValue(context.getClassificationNames());
+            String classificationNames = AtlasStructType.AtlasAttribute.escapeIndexQueryValue(context.getClassificationNames(), true);
             if (indexQuery.length() != 0) {
                 indexQuery.append(" AND ");
             }
diff --git a/repository/src/main/java/org/apache/atlas/discovery/SearchContext.java b/repository/src/main/java/org/apache/atlas/discovery/SearchContext.java
index 2cb287f..aa49121 100644
--- a/repository/src/main/java/org/apache/atlas/discovery/SearchContext.java
+++ b/repository/src/main/java/org/apache/atlas/discovery/SearchContext.java
@@ -144,7 +144,7 @@ public class SearchContext {
             }
 
             if (CollectionUtils.isNotEmpty(classificationTypeAndSubTypes)) {
-                classificationTypeAndSubTypesQryStr = AtlasAttribute.escapeIndexQueryValue(classificationTypeAndSubTypes);
+                classificationTypeAndSubTypesQryStr = AtlasAttribute.escapeIndexQueryValue(classificationTypeAndSubTypes, true);
             }
         } else {
             classificationTypeAndSubTypes       = Collections.emptySet();
@@ -171,7 +171,7 @@ public class SearchContext {
             }
 
             if (CollectionUtils.isNotEmpty(typeAndSubTypes)) {
-                typeAndSubTypesQryStr = AtlasAttribute.escapeIndexQueryValue(typeAndSubTypes);
+                typeAndSubTypesQryStr = AtlasAttribute.escapeIndexQueryValue(typeAndSubTypes, true);
             }
         } else {
             typeAndSubTypes       = Collections.emptySet();
diff --git a/repository/src/main/java/org/apache/atlas/discovery/SearchProcessor.java b/repository/src/main/java/org/apache/atlas/discovery/SearchProcessor.java
index da9dd66..01daf53 100644
--- a/repository/src/main/java/org/apache/atlas/discovery/SearchProcessor.java
+++ b/repository/src/main/java/org/apache/atlas/discovery/SearchProcessor.java
@@ -1150,24 +1150,6 @@ public abstract class SearchProcessor {
 
     private static boolean isIndexQuerySpecialChar(char c) {
         switch (c) {
-            case '+':
-            case '-':
-            case '&':
-            case '|':
-            case '!':
-            case '(':
-            case ')':
-            case '{':
-            case '}':
-            case '[':
-            case ']':
-            case '^':
-            case '"':
-            case '~':
-            case '*':
-            case '?':
-            case ':':
-            case '/':
             case '#':
             case '$':
             case '%':