Skip to content

Commit 4e434e8

Browse files
committed
Added IEQUAL operator to support case insensitive searches
1 parent 0187fc6 commit 4e434e8

File tree

8 files changed

+42
-9
lines changed

8 files changed

+42
-9
lines changed

datahub-graphql-core/src/main/resources/search.graphql

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,11 @@ enum FilterOperator {
575575
Represent the relation: URN field matches any nested child or parent in addition to the given URN
576576
"""
577577
RELATED_INCL
578+
579+
"""
580+
Represent the relation: field = value (case-insensitive), e.g. platform = HDFS
581+
"""
582+
IEQUAL
578583
}
579584

580585
"""

docs/api/restli/restli-overview.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1203,6 +1203,7 @@ where valid conditions include
12031203
- CONTAIN
12041204
- END_WITH
12051205
- EQUAL
1206+
- IEQUAL (Supports case insensitive equals)
12061207
- GREATER_THAN
12071208
- GREATER_THAN_OR_EQUAL_TO
12081209
- LESS_THAN

metadata-io/src/main/java/com/linkedin/metadata/search/utils/ESUtils.java

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,9 @@ private static QueryBuilder getQueryBuilderFromCriterionForFieldToExpand(
551551
}
552552
return orQueryBuilder;
553553
}
554+
private static boolean isCaseInsensitiveSearchEnabled(Condition condition) {
555+
return condition == Condition.IEQUAL;
556+
}
554557

555558
@Nonnull
556559
private static QueryBuilder getQueryBuilderFromCriterionForSingleField(
@@ -573,9 +576,10 @@ private static QueryBuilder getQueryBuilderFromCriterionForSingleField(
573576
.must(QueryBuilders.existsQuery(fieldName))
574577
.queryName(queryName != null ? queryName : fieldName);
575578
} else if (criterion.hasValues()) {
576-
if (condition == Condition.EQUAL) {
579+
if (condition == Condition.EQUAL || condition ==Condition.IEQUAL) {
580+
boolean enableCaseInsensitiveSearches = isCaseInsensitiveSearchEnabled(condition);
577581
return buildEqualsConditionFromCriterion(
578-
fieldName, criterion, isTimeseries, searchableFieldTypes, aspectRetriever)
582+
fieldName, criterion, isTimeseries, searchableFieldTypes, aspectRetriever, enableCaseInsensitiveSearches)
579583
.queryName(queryName != null ? queryName : fieldName);
580584
} else if (RANGE_QUERY_CONDITIONS.contains(condition)) {
581585
return buildRangeQueryFromCriterion(
@@ -605,7 +609,7 @@ private static QueryBuilder getQueryBuilderFromCriterionForSingleField(
605609
.rewrite(
606610
opContext,
607611
buildEqualsConditionFromCriterion(
608-
fieldName, criterion, isTimeseries, searchableFieldTypes, aspectRetriever))
612+
fieldName, criterion, isTimeseries, searchableFieldTypes, aspectRetriever,false))
609613
.queryName(queryName != null ? queryName : fieldName);
610614
}
611615
}
@@ -670,9 +674,9 @@ private static QueryBuilder buildEqualsConditionFromCriterion(
670674
@Nonnull final Criterion criterion,
671675
final boolean isTimeseries,
672676
final Map<String, Set<SearchableAnnotation.FieldType>> searchableFieldTypes,
673-
@Nonnull AspectRetriever aspectRetriever) {
677+
@Nonnull AspectRetriever aspectRetriever,boolean enableCaseInsensitiveSearches ) {
674678
return buildEqualsConditionFromCriterionWithValues(
675-
fieldName, criterion, isTimeseries, searchableFieldTypes, aspectRetriever);
679+
fieldName, criterion, isTimeseries, searchableFieldTypes, aspectRetriever, enableCaseInsensitiveSearches);
676680
}
677681

678682
/**
@@ -684,7 +688,7 @@ private static QueryBuilder buildEqualsConditionFromCriterionWithValues(
684688
@Nonnull final Criterion criterion,
685689
final boolean isTimeseries,
686690
final Map<String, Set<SearchableAnnotation.FieldType>> searchableFieldTypes,
687-
@Nonnull AspectRetriever aspectRetriever) {
691+
@Nonnull AspectRetriever aspectRetriever,boolean enableCaseInsensitiveSearches) {
688692
Set<String> fieldTypes = getFieldTypes(searchableFieldTypes, fieldName, aspectRetriever);
689693
if (fieldTypes.size() > 1) {
690694
log.warn(
@@ -704,6 +708,20 @@ private static QueryBuilder buildEqualsConditionFromCriterionWithValues(
704708
criterion.getValues().stream().map(Double::parseDouble).collect(Collectors.toList());
705709
return QueryBuilders.termsQuery(fieldName, doubleValues).queryName(fieldName);
706710
}
711+
712+
if (enableCaseInsensitiveSearches) {
713+
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
714+
criterion.getValues().forEach(value ->
715+
boolQuery.should(
716+
QueryBuilders.termQuery(
717+
toKeywordField(criterion.getField(), isTimeseries, aspectRetriever),
718+
value.trim()
719+
).caseInsensitive(true)
720+
)
721+
);
722+
return boolQuery;
723+
}
724+
707725
return QueryBuilders.termsQuery(
708726
toKeywordField(criterion.getField(), isTimeseries, aspectRetriever),
709727
criterion.getValues())

metadata-models/src/main/pegasus/com/linkedin/metadata/query/filter/Condition.pdl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ enum Condition {
2020
*/
2121
EQUAL
2222

23+
/**
24+
* Represent the relation: field = value, e.g. platform = hdfs
25+
*/
26+
IEQUAL
27+
2328
/**
2429
* Represent the relation: field is null, e.g. platform is null
2530
*/

metadata-service/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1291,6 +1291,7 @@ where valid conditions include
12911291
- CONTAIN
12921292
- END_WITH
12931293
- EQUAL
1294+
- IEQUAL (Supports case insensitive equals)
12941295
- GREATER_THAN
12951296
- GREATER_THAN_OR_EQUAL_TO
12961297
- LESS_THAN

metadata-service/restli-api/src/main/snapshot/com.linkedin.analytics.analytics.snapshot.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,14 @@
5656
"type" : "enum",
5757
"name" : "Condition",
5858
"doc" : "The matching condition in a filter criterion",
59-
"symbols" : [ "CONTAIN", "END_WITH", "EQUAL", "IS_NULL", "EXISTS", "GREATER_THAN", "GREATER_THAN_OR_EQUAL_TO", "IN", "LESS_THAN", "LESS_THAN_OR_EQUAL_TO", "START_WITH", "DESCENDANTS_INCL", "ANCESTORS_INCL", "RELATED_INCL" ],
59+
"symbols" : [ "CONTAIN", "END_WITH", "EQUAL","IEQUAL", "IS_NULL", "EXISTS", "GREATER_THAN", "GREATER_THAN_OR_EQUAL_TO", "IN", "LESS_THAN", "LESS_THAN_OR_EQUAL_TO", "START_WITH", "DESCENDANTS_INCL", "ANCESTORS_INCL", "RELATED_INCL" ],
6060
"symbolDocs" : {
6161
"ANCESTORS_INCL" : "Represent the relation: URN field matches any nested parent in addition to the given URN",
6262
"CONTAIN" : "Represent the relation: String field contains value, e.g. name contains Profile",
6363
"DESCENDANTS_INCL" : "Represent the relation: URN field any nested children in addition to the given URN",
6464
"END_WITH" : "Represent the relation: String field ends with value, e.g. name ends with Event",
6565
"EQUAL" : "Represent the relation: field = value, e.g. platform = hdfs",
66+
"IEQUAL" : "Represent the relation: case-insensitive field = value, e.g. platform = hdfs",
6667
"EXISTS" : "Represents the relation: field exists and is non-empty, e.g. owners is not null and != [] (empty)",
6768
"GREATER_THAN" : "Represent the relation greater than, e.g. ownerCount > 5",
6869
"GREATER_THAN_OR_EQUAL_TO" : "Represent the relation greater than or equal to, e.g. ownerCount >= 5",

metadata-service/restli-api/src/main/snapshot/com.linkedin.entity.aspects.snapshot.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,13 +162,14 @@
162162
"type" : "enum",
163163
"name" : "Condition",
164164
"doc" : "The matching condition in a filter criterion",
165-
"symbols" : [ "CONTAIN", "END_WITH", "EQUAL", "IS_NULL", "EXISTS", "GREATER_THAN", "GREATER_THAN_OR_EQUAL_TO", "IN", "LESS_THAN", "LESS_THAN_OR_EQUAL_TO", "START_WITH", "DESCENDANTS_INCL", "ANCESTORS_INCL", "RELATED_INCL" ],
165+
"symbols" : [ "CONTAIN", "END_WITH", "EQUAL", "IEQUAL","IS_NULL", "EXISTS", "GREATER_THAN", "GREATER_THAN_OR_EQUAL_TO", "IN", "LESS_THAN", "LESS_THAN_OR_EQUAL_TO", "START_WITH", "DESCENDANTS_INCL", "ANCESTORS_INCL", "RELATED_INCL" ],
166166
"symbolDocs" : {
167167
"ANCESTORS_INCL" : "Represent the relation: URN field matches any nested parent in addition to the given URN",
168168
"CONTAIN" : "Represent the relation: String field contains value, e.g. name contains Profile",
169169
"DESCENDANTS_INCL" : "Represent the relation: URN field any nested children in addition to the given URN",
170170
"END_WITH" : "Represent the relation: String field ends with value, e.g. name ends with Event",
171171
"EQUAL" : "Represent the relation: field = value, e.g. platform = hdfs",
172+
"IEQUAL" : "Represent the relation: field = value, e.g. platform = hdfs",
172173
"EXISTS" : "Represents the relation: field exists and is non-empty, e.g. owners is not null and != [] (empty)",
173174
"GREATER_THAN" : "Represent the relation greater than, e.g. ownerCount > 5",
174175
"GREATER_THAN_OR_EQUAL_TO" : "Represent the relation greater than or equal to, e.g. ownerCount >= 5",

metadata-service/restli-api/src/main/snapshot/com.linkedin.entity.entities.snapshot.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6057,13 +6057,14 @@
60576057
"name" : "Condition",
60586058
"namespace" : "com.linkedin.metadata.query.filter",
60596059
"doc" : "The matching condition in a filter criterion",
6060-
"symbols" : [ "CONTAIN", "END_WITH", "EQUAL", "IS_NULL", "EXISTS", "GREATER_THAN", "GREATER_THAN_OR_EQUAL_TO", "IN", "LESS_THAN", "LESS_THAN_OR_EQUAL_TO", "START_WITH", "DESCENDANTS_INCL", "ANCESTORS_INCL", "RELATED_INCL" ],
6060+
"symbols" : [ "CONTAIN", "END_WITH", "EQUAL","IEQUAL", "IS_NULL", "EXISTS", "GREATER_THAN", "GREATER_THAN_OR_EQUAL_TO", "IN", "LESS_THAN", "LESS_THAN_OR_EQUAL_TO", "START_WITH", "DESCENDANTS_INCL", "ANCESTORS_INCL", "RELATED_INCL" ],
60616061
"symbolDocs" : {
60626062
"ANCESTORS_INCL" : "Represent the relation: URN field matches any nested parent in addition to the given URN",
60636063
"CONTAIN" : "Represent the relation: String field contains value, e.g. name contains Profile",
60646064
"DESCENDANTS_INCL" : "Represent the relation: URN field any nested children in addition to the given URN",
60656065
"END_WITH" : "Represent the relation: String field ends with value, e.g. name ends with Event",
60666066
"EQUAL" : "Represent the relation: field = value, e.g. platform = hdfs",
6067+
"IEQUAL" : "Represent the relation: field = value, e.g. platform = hdfs",
60676068
"EXISTS" : "Represents the relation: field exists and is non-empty, e.g. owners is not null and != [] (empty)",
60686069
"GREATER_THAN" : "Represent the relation greater than, e.g. ownerCount > 5",
60696070
"GREATER_THAN_OR_EQUAL_TO" : "Represent the relation greater than or equal to, e.g. ownerCount >= 5",

0 commit comments

Comments
 (0)