mirror of
https://github.com/datahub-project/datahub.git
synced 2025-12-26 01:18:20 +00:00
refactor(platform): Refactoring ES Utils, adding EXISTS condition support to Filter Criterion (#7832)
This commit is contained in:
parent
90f653b622
commit
73a12379ae
@ -29,6 +29,9 @@ import static com.linkedin.metadata.search.elasticsearch.query.request.SearchFie
|
||||
import static com.linkedin.metadata.search.utils.SearchUtils.isUrn;
|
||||
|
||||
|
||||
/**
|
||||
* TODO: Add more robust unit tests for this critical class.
|
||||
*/
|
||||
@Slf4j
|
||||
public class ESUtils {
|
||||
|
||||
@ -135,85 +138,27 @@ public class ESUtils {
|
||||
* @param criterion {@link Criterion} single criterion which contains field, value and a comparison operator
|
||||
*/
|
||||
@Nonnull
|
||||
public static QueryBuilder getQueryBuilderFromCriterion(@Nonnull Criterion criterion, boolean isTimeseries) {
|
||||
String fieldName = toFacetField(criterion.getField());
|
||||
public static QueryBuilder getQueryBuilderFromCriterion(@Nonnull final Criterion criterion, boolean isTimeseries) {
|
||||
final String fieldName = toFacetField(criterion.getField());
|
||||
|
||||
Optional<String[]> pairMatch = Arrays.stream(EDITABLE_FIELD_TO_QUERY_PAIRS)
|
||||
.filter(pair -> Arrays.stream(pair).anyMatch(pairValue -> pairValue.equals(fieldName)))
|
||||
/*
|
||||
* Check the field-name for a "sibling" field, or one which should ALWAYS
|
||||
* be matched in disjunction with the targeted field (OR).
|
||||
*
|
||||
* This essentially equates to filter expansion based on a particular field.
|
||||
* First we handle this expansion, if required, otherwise we build the filter as usual
|
||||
* without expansion.
|
||||
*/
|
||||
final Optional<String[]> maybeFieldToExpand = Arrays.stream(EDITABLE_FIELD_TO_QUERY_PAIRS)
|
||||
.filter(pair -> Arrays.asList(pair).contains(fieldName))
|
||||
.findFirst();
|
||||
|
||||
if (pairMatch.isPresent()) {
|
||||
final BoolQueryBuilder orQueryBuilder = new BoolQueryBuilder();
|
||||
String[] pairMatchValue = pairMatch.get();
|
||||
for (String field: pairMatchValue) {
|
||||
Criterion criterionToQuery = new Criterion();
|
||||
criterionToQuery.setCondition(criterion.getCondition());
|
||||
criterionToQuery.setNegated(criterion.isNegated());
|
||||
criterionToQuery.setValue(criterion.getValue());
|
||||
criterionToQuery.setValues(criterion.getValues());
|
||||
criterionToQuery.setField(toKeywordField(field, isTimeseries));
|
||||
orQueryBuilder.should(getQueryBuilderFromCriterionForSingleField(criterionToQuery, isTimeseries));
|
||||
}
|
||||
return orQueryBuilder;
|
||||
if (maybeFieldToExpand.isPresent()) {
|
||||
return getQueryBuilderFromCriterionForFieldToExpand(maybeFieldToExpand.get(), criterion, isTimeseries);
|
||||
}
|
||||
|
||||
return getQueryBuilderFromCriterionForSingleField(criterion, isTimeseries);
|
||||
}
|
||||
@Nonnull
|
||||
public static QueryBuilder getQueryBuilderFromCriterionForSingleField(@Nonnull Criterion criterion, @Nonnull boolean isTimeseries) {
|
||||
final Condition condition = criterion.getCondition();
|
||||
String fieldName = toFacetField(criterion.getField());
|
||||
|
||||
if (condition == Condition.EQUAL) {
|
||||
// If values is set, use terms query to match one of the values
|
||||
if (!criterion.getValues().isEmpty()) {
|
||||
if (BOOLEAN_FIELDS.contains(fieldName) && criterion.getValues().size() == 1) {
|
||||
return QueryBuilders.termQuery(fieldName, Boolean.parseBoolean(criterion.getValues().get(0)))
|
||||
.queryName(fieldName);
|
||||
}
|
||||
return QueryBuilders.termsQuery(toKeywordField(criterion.getField(), isTimeseries), criterion.getValues())
|
||||
.queryName(fieldName);
|
||||
}
|
||||
|
||||
// TODO(https://github.com/datahub-project/datahub-gma/issues/51): support multiple values a field can take without using
|
||||
// delimiters like comma. This is a hack to support equals with URN that has a comma in it.
|
||||
if (isUrn(criterion.getValue())) {
|
||||
return QueryBuilders.matchQuery(toKeywordField(criterion.getField(), isTimeseries), criterion.getValue().trim())
|
||||
.queryName(fieldName)
|
||||
.analyzer(KEYWORD_ANALYZER);
|
||||
}
|
||||
BoolQueryBuilder filters = new BoolQueryBuilder();
|
||||
// Cannot assume the existence of a .keyword or other subfield (unless contains `.`)
|
||||
// Cannot assume the type of the underlying field or subfield thus KEYWORD_ANALYZER is forced
|
||||
List<String> fields = criterion.getField().contains(".") ? List.of(criterion.getField())
|
||||
: List.of(criterion.getField(), criterion.getField() + ".*");
|
||||
Arrays.stream(criterion.getValue().trim().split("\\s*,\\s*"))
|
||||
.forEach(elem -> filters.should(QueryBuilders.multiMatchQuery(elem, fields.toArray(new String[0]))
|
||||
.queryName(fieldName)
|
||||
.analyzer(KEYWORD_ANALYZER)));
|
||||
return filters;
|
||||
} else if (condition == Condition.IS_NULL) {
|
||||
return QueryBuilders.boolQuery().mustNot(QueryBuilders.existsQuery(criterion.getField())).queryName(fieldName);
|
||||
} else if (condition == Condition.GREATER_THAN) {
|
||||
return QueryBuilders.rangeQuery(criterion.getField()).gt(criterion.getValue().trim()).queryName(fieldName);
|
||||
} else if (condition == Condition.GREATER_THAN_OR_EQUAL_TO) {
|
||||
return QueryBuilders.rangeQuery(criterion.getField()).gte(criterion.getValue().trim()).queryName(fieldName);
|
||||
} else if (condition == Condition.LESS_THAN) {
|
||||
return QueryBuilders.rangeQuery(criterion.getField()).lt(criterion.getValue().trim()).queryName(fieldName);
|
||||
} else if (condition == Condition.LESS_THAN_OR_EQUAL_TO) {
|
||||
return QueryBuilders.rangeQuery(criterion.getField()).lte(criterion.getValue().trim()).queryName(fieldName);
|
||||
} else if (condition == Condition.CONTAIN) {
|
||||
return QueryBuilders.wildcardQuery(toKeywordField(criterion.getField(), isTimeseries),
|
||||
"*" + ESUtils.escapeReservedCharacters(criterion.getValue().trim()) + "*").queryName(fieldName);
|
||||
} else if (condition == Condition.START_WITH) {
|
||||
return QueryBuilders.wildcardQuery(toKeywordField(criterion.getField(), isTimeseries),
|
||||
ESUtils.escapeReservedCharacters(criterion.getValue().trim()) + "*").queryName(fieldName);
|
||||
} else if (condition == Condition.END_WITH) {
|
||||
return QueryBuilders.wildcardQuery(toKeywordField(criterion.getField(), isTimeseries),
|
||||
"*" + ESUtils.escapeReservedCharacters(criterion.getValue().trim())).queryName(fieldName);
|
||||
}
|
||||
throw new UnsupportedOperationException("Unsupported condition: " + condition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates source field of search query with the sort order as per the criterion provided.
|
||||
@ -256,7 +201,7 @@ public class ESUtils {
|
||||
return input;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Nonnull
|
||||
public static String toFacetField(@Nonnull final String filterField) {
|
||||
return filterField.replace(ESUtils.KEYWORD_SUFFIX, "");
|
||||
}
|
||||
@ -298,4 +243,126 @@ public class ESUtils {
|
||||
searchSourceBuilder.pointInTimeBuilder(pointInTimeBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private static QueryBuilder getQueryBuilderFromCriterionForFieldToExpand(
|
||||
@Nonnull final String[] fields,
|
||||
@Nonnull final Criterion criterion,
|
||||
final boolean isTimeseries) {
|
||||
final BoolQueryBuilder orQueryBuilder = new BoolQueryBuilder();
|
||||
for (String field : fields) {
|
||||
Criterion criterionToQuery = new Criterion();
|
||||
criterionToQuery.setCondition(criterion.getCondition());
|
||||
criterionToQuery.setNegated(criterion.isNegated());
|
||||
criterionToQuery.setValue(criterion.getValue());
|
||||
criterionToQuery.setValues(criterion.getValues());
|
||||
criterionToQuery.setField(toKeywordField(field, isTimeseries));
|
||||
orQueryBuilder.should(getQueryBuilderFromCriterionForSingleField(criterionToQuery, isTimeseries));
|
||||
}
|
||||
return orQueryBuilder;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private static QueryBuilder getQueryBuilderFromCriterionForSingleField(@Nonnull Criterion criterion, @Nonnull boolean isTimeseries) {
|
||||
final Condition condition = criterion.getCondition();
|
||||
final String fieldName = toFacetField(criterion.getField());
|
||||
|
||||
if (condition == Condition.EQUAL) {
|
||||
return buildEqualsConditionFromCriterion(fieldName, criterion, isTimeseries);
|
||||
} else if (condition == Condition.IS_NULL) {
|
||||
return QueryBuilders.boolQuery().mustNot(QueryBuilders.existsQuery(criterion.getField())).queryName(fieldName);
|
||||
} else if (condition == Condition.EXISTS) {
|
||||
return QueryBuilders.boolQuery().must(QueryBuilders.existsQuery(criterion.getField())).queryName(fieldName);
|
||||
// TODO: Support multi-match on the following operators (using new 'values' field)
|
||||
} else if (condition == Condition.GREATER_THAN) {
|
||||
return QueryBuilders.rangeQuery(criterion.getField()).gt(criterion.getValue().trim()).queryName(fieldName);
|
||||
} else if (condition == Condition.GREATER_THAN_OR_EQUAL_TO) {
|
||||
return QueryBuilders.rangeQuery(criterion.getField()).gte(criterion.getValue().trim()).queryName(fieldName);
|
||||
} else if (condition == Condition.LESS_THAN) {
|
||||
return QueryBuilders.rangeQuery(criterion.getField()).lt(criterion.getValue().trim()).queryName(fieldName);
|
||||
} else if (condition == Condition.LESS_THAN_OR_EQUAL_TO) {
|
||||
return QueryBuilders.rangeQuery(criterion.getField()).lte(criterion.getValue().trim()).queryName(fieldName);
|
||||
} else if (condition == Condition.CONTAIN) {
|
||||
return QueryBuilders.wildcardQuery(toKeywordField(criterion.getField(), isTimeseries),
|
||||
"*" + ESUtils.escapeReservedCharacters(criterion.getValue().trim()) + "*").queryName(fieldName);
|
||||
} else if (condition == Condition.START_WITH) {
|
||||
return QueryBuilders.wildcardQuery(toKeywordField(criterion.getField(), isTimeseries),
|
||||
ESUtils.escapeReservedCharacters(criterion.getValue().trim()) + "*").queryName(fieldName);
|
||||
} else if (condition == Condition.END_WITH) {
|
||||
return QueryBuilders.wildcardQuery(toKeywordField(criterion.getField(), isTimeseries),
|
||||
"*" + ESUtils.escapeReservedCharacters(criterion.getValue().trim())).queryName(fieldName);
|
||||
}
|
||||
throw new UnsupportedOperationException("Unsupported condition: " + condition);
|
||||
}
|
||||
|
||||
private static QueryBuilder buildEqualsConditionFromCriterion(
|
||||
@Nonnull final String fieldName,
|
||||
@Nonnull final Criterion criterion,
|
||||
final boolean isTimeseries) {
|
||||
/*
|
||||
* If the newer 'values' field of Criterion.pdl is set, then we
|
||||
* handle using the following code to allow multi-match.
|
||||
*/
|
||||
if (!criterion.getValues().isEmpty()) {
|
||||
return buildEqualsConditionFromCriterionWithValues(fieldName, criterion, isTimeseries);
|
||||
}
|
||||
/*
|
||||
* Otherwise, we are likely using the deprecated 'value' field.
|
||||
* We handle using the legacy code path below.
|
||||
*/
|
||||
return buildEqualsFromCriterionWithValue(fieldName, criterion, isTimeseries);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an instance of {@link QueryBuilder} representing an EQUALS condition which
|
||||
* was created using the new multi-match 'values' field of Criterion.pdl model.
|
||||
*/
|
||||
private static QueryBuilder buildEqualsConditionFromCriterionWithValues(
|
||||
@Nonnull final String fieldName,
|
||||
@Nonnull final Criterion criterion,
|
||||
final boolean isTimeseries) {
|
||||
if (BOOLEAN_FIELDS.contains(fieldName) && criterion.getValues().size() == 1) {
|
||||
// Handle special-cased Boolean fields.
|
||||
// here we special case boolean fields we recognize the names of and hard-cast
|
||||
// the first provided value to a boolean to do the comparison.
|
||||
// Ideally, we should detect the type of the field from the entity-registry in order
|
||||
// to determine how to cast.
|
||||
return QueryBuilders.termQuery(fieldName, Boolean.parseBoolean(criterion.getValues().get(0)))
|
||||
.queryName(fieldName);
|
||||
}
|
||||
return QueryBuilders.termsQuery(toKeywordField(criterion.getField(), isTimeseries), criterion.getValues())
|
||||
.queryName(fieldName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an instance of {@link QueryBuilder} representing an EQUALS condition which
|
||||
* was created using the deprecated 'value' field of Criterion.pdl model.
|
||||
*
|
||||
* Previously, we supported comma-separate values inside of a single string field,
|
||||
* thus we have to account for splitting and matching against each value below.
|
||||
*
|
||||
* For all new code, we should be using the new 'values' field for performing multi-match. This
|
||||
* is simply retained for backwards compatibility of the search API.
|
||||
*/
|
||||
private static QueryBuilder buildEqualsFromCriterionWithValue(
|
||||
@Nonnull final String fieldName,
|
||||
@Nonnull final Criterion criterion,
|
||||
final boolean isTimeseries) {
|
||||
// If the value is an URN style value, then we do not attempt to split it by comma (for obvious reasons)
|
||||
if (isUrn(criterion.getValue())) {
|
||||
return QueryBuilders.matchQuery(toKeywordField(criterion.getField(), isTimeseries), criterion.getValue().trim())
|
||||
.queryName(fieldName)
|
||||
.analyzer(KEYWORD_ANALYZER);
|
||||
}
|
||||
final BoolQueryBuilder filters = new BoolQueryBuilder();
|
||||
// Cannot assume the existence of a .keyword or other subfield (unless contains `.`)
|
||||
// Cannot assume the type of the underlying field or subfield thus KEYWORD_ANALYZER is forced
|
||||
List<String> fields = criterion.getField().contains(".") ? List.of(criterion.getField())
|
||||
: List.of(criterion.getField(), criterion.getField() + ".*");
|
||||
Arrays.stream(criterion.getValue().trim().split("\\s*,\\s*"))
|
||||
.forEach(elem -> filters.should(QueryBuilders.multiMatchQuery(elem, fields.toArray(new String[0]))
|
||||
.queryName(fieldName)
|
||||
.analyzer(KEYWORD_ANALYZER)));
|
||||
return filters;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,262 @@
|
||||
package com.linkedin.metadata.search.utils;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.linkedin.data.template.StringArray;
|
||||
import com.linkedin.metadata.query.filter.Condition;
|
||||
import com.linkedin.metadata.query.filter.Criterion;
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
|
||||
public class ESUtilsTest {
|
||||
|
||||
private static final String FIELD_TO_EXPAND = "fieldTags";
|
||||
|
||||
@Test
|
||||
public void testGetQueryBuilderFromCriterionEqualsValues() {
|
||||
|
||||
final Criterion singleValueCriterion = new Criterion()
|
||||
.setField("myTestField")
|
||||
.setCondition(Condition.EQUAL)
|
||||
.setValues(new StringArray(ImmutableList.of(
|
||||
"value1"
|
||||
)));
|
||||
|
||||
QueryBuilder result = ESUtils.getQueryBuilderFromCriterion(singleValueCriterion, false);
|
||||
String expected =
|
||||
"{\n"
|
||||
+ " \"terms\" : {\n"
|
||||
+ " \"myTestField.keyword\" : [\n"
|
||||
+ " \"value1\"\n"
|
||||
+ " ],\n"
|
||||
+ " \"boost\" : 1.0,\n"
|
||||
+ " \"_name\" : \"myTestField\"\n"
|
||||
+ " }\n"
|
||||
+ "}";
|
||||
Assert.assertEquals(result.toString(), expected);
|
||||
|
||||
final Criterion multiValueCriterion = new Criterion()
|
||||
.setField("myTestField")
|
||||
.setCondition(Condition.EQUAL)
|
||||
.setValues(new StringArray(ImmutableList.of(
|
||||
"value1", "value2"
|
||||
)));
|
||||
|
||||
result = ESUtils.getQueryBuilderFromCriterion(multiValueCriterion, false);
|
||||
expected =
|
||||
"{\n"
|
||||
+ " \"terms\" : {\n"
|
||||
+ " \"myTestField.keyword\" : [\n"
|
||||
+ " \"value1\",\n"
|
||||
+ " \"value2\"\n"
|
||||
+ " ],\n"
|
||||
+ " \"boost\" : 1.0,\n"
|
||||
+ " \"_name\" : \"myTestField\"\n"
|
||||
+ " }\n"
|
||||
+ "}";
|
||||
Assert.assertEquals(result.toString(), expected);
|
||||
|
||||
final Criterion timeseriesField = new Criterion()
|
||||
.setField("myTestField")
|
||||
.setCondition(Condition.EQUAL)
|
||||
.setValues(new StringArray(ImmutableList.of(
|
||||
"value1", "value2"
|
||||
)));
|
||||
|
||||
result = ESUtils.getQueryBuilderFromCriterion(timeseriesField, true);
|
||||
expected = "{\n"
|
||||
+ " \"terms\" : {\n"
|
||||
+ " \"myTestField\" : [\n"
|
||||
+ " \"value1\",\n"
|
||||
+ " \"value2\"\n"
|
||||
+ " ],\n"
|
||||
+ " \"boost\" : 1.0,\n"
|
||||
+ " \"_name\" : \"myTestField\"\n"
|
||||
+ " }\n"
|
||||
+ "}";
|
||||
Assert.assertEquals(result.toString(), expected);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetQueryBuilderFromCriterionExists() {
|
||||
final Criterion singleValueCriterion = new Criterion()
|
||||
.setField("myTestField")
|
||||
.setCondition(Condition.EXISTS);
|
||||
|
||||
QueryBuilder result = ESUtils.getQueryBuilderFromCriterion(singleValueCriterion, false);
|
||||
String expected =
|
||||
"{\n"
|
||||
+ " \"bool\" : {\n"
|
||||
+ " \"must\" : [\n"
|
||||
+ " {\n"
|
||||
+ " \"exists\" : {\n"
|
||||
+ " \"field\" : \"myTestField\",\n"
|
||||
+ " \"boost\" : 1.0\n"
|
||||
+ " }\n"
|
||||
+ " }\n"
|
||||
+ " ],\n"
|
||||
+ " \"adjust_pure_negative\" : true,\n"
|
||||
+ " \"boost\" : 1.0,\n"
|
||||
+ " \"_name\" : \"myTestField\"\n"
|
||||
+ " }\n"
|
||||
+ "}";
|
||||
Assert.assertEquals(result.toString(), expected);
|
||||
|
||||
// No diff in the timeseries field case for this condition.
|
||||
final Criterion timeseriesField = new Criterion()
|
||||
.setField("myTestField")
|
||||
.setCondition(Condition.EXISTS);
|
||||
|
||||
result = ESUtils.getQueryBuilderFromCriterion(timeseriesField, true);
|
||||
expected = "{\n"
|
||||
+ " \"bool\" : {\n"
|
||||
+ " \"must\" : [\n"
|
||||
+ " {\n"
|
||||
+ " \"exists\" : {\n"
|
||||
+ " \"field\" : \"myTestField\",\n"
|
||||
+ " \"boost\" : 1.0\n"
|
||||
+ " }\n"
|
||||
+ " }\n"
|
||||
+ " ],\n"
|
||||
+ " \"adjust_pure_negative\" : true,\n"
|
||||
+ " \"boost\" : 1.0,\n"
|
||||
+ " \"_name\" : \"myTestField\"\n"
|
||||
+ " }\n"
|
||||
+ "}";
|
||||
Assert.assertEquals(result.toString(), expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetQueryBuilderFromCriterionIsNull() {
|
||||
final Criterion singleValueCriterion = new Criterion()
|
||||
.setField("myTestField")
|
||||
.setCondition(Condition.IS_NULL);
|
||||
|
||||
QueryBuilder result = ESUtils.getQueryBuilderFromCriterion(singleValueCriterion, false);
|
||||
String expected =
|
||||
"{\n"
|
||||
+ " \"bool\" : {\n"
|
||||
+ " \"must_not\" : [\n"
|
||||
+ " {\n"
|
||||
+ " \"exists\" : {\n"
|
||||
+ " \"field\" : \"myTestField\",\n"
|
||||
+ " \"boost\" : 1.0\n"
|
||||
+ " }\n"
|
||||
+ " }\n"
|
||||
+ " ],\n"
|
||||
+ " \"adjust_pure_negative\" : true,\n"
|
||||
+ " \"boost\" : 1.0,\n"
|
||||
+ " \"_name\" : \"myTestField\"\n"
|
||||
+ " }\n"
|
||||
+ "}";
|
||||
Assert.assertEquals(result.toString(), expected);
|
||||
|
||||
// No diff in the timeseries case for this condition
|
||||
final Criterion timeseriesField = new Criterion()
|
||||
.setField("myTestField")
|
||||
.setCondition(Condition.IS_NULL);
|
||||
|
||||
result = ESUtils.getQueryBuilderFromCriterion(timeseriesField, true);
|
||||
expected = "{\n"
|
||||
+ " \"bool\" : {\n"
|
||||
+ " \"must_not\" : [\n"
|
||||
+ " {\n"
|
||||
+ " \"exists\" : {\n"
|
||||
+ " \"field\" : \"myTestField\",\n"
|
||||
+ " \"boost\" : 1.0\n"
|
||||
+ " }\n"
|
||||
+ " }\n"
|
||||
+ " ],\n"
|
||||
+ " \"adjust_pure_negative\" : true,\n"
|
||||
+ " \"boost\" : 1.0,\n"
|
||||
+ " \"_name\" : \"myTestField\"\n"
|
||||
+ " }\n"
|
||||
+ "}";
|
||||
Assert.assertEquals(result.toString(), expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetQueryBuilderFromCriterionFieldToExpand() {
|
||||
|
||||
final Criterion singleValueCriterion = new Criterion()
|
||||
.setField(FIELD_TO_EXPAND)
|
||||
.setCondition(Condition.EQUAL)
|
||||
.setValue("") // Ignored
|
||||
.setValues(new StringArray(ImmutableList.of(
|
||||
"value1"
|
||||
)));
|
||||
|
||||
// Ensure that the query is expanded!
|
||||
QueryBuilder result = ESUtils.getQueryBuilderFromCriterion(singleValueCriterion, false);
|
||||
String expected = "{\n"
|
||||
+ " \"bool\" : {\n"
|
||||
+ " \"should\" : [\n"
|
||||
+ " {\n"
|
||||
+ " \"terms\" : {\n"
|
||||
+ " \"fieldTags.keyword\" : [\n"
|
||||
+ " \"value1\"\n"
|
||||
+ " ],\n"
|
||||
+ " \"boost\" : 1.0,\n"
|
||||
+ " \"_name\" : \"fieldTags\"\n"
|
||||
+ " }\n"
|
||||
+ " },\n"
|
||||
+ " {\n"
|
||||
+ " \"terms\" : {\n"
|
||||
+ " \"editedFieldTags.keyword\" : [\n"
|
||||
+ " \"value1\"\n"
|
||||
+ " ],\n"
|
||||
+ " \"boost\" : 1.0,\n"
|
||||
+ " \"_name\" : \"editedFieldTags\"\n"
|
||||
+ " }\n"
|
||||
+ " }\n"
|
||||
+ " ],\n"
|
||||
+ " \"adjust_pure_negative\" : true,\n"
|
||||
+ " \"boost\" : 1.0\n"
|
||||
+ " }\n"
|
||||
+ "}";
|
||||
Assert.assertEquals(result.toString(), expected);
|
||||
|
||||
final Criterion timeseriesField = new Criterion()
|
||||
.setField(FIELD_TO_EXPAND)
|
||||
.setCondition(Condition.EQUAL)
|
||||
.setValue("") // Ignored
|
||||
.setValues(new StringArray(ImmutableList.of(
|
||||
"value1", "value2"
|
||||
)));
|
||||
|
||||
// Ensure that the query is expanded without keyword.
|
||||
result = ESUtils.getQueryBuilderFromCriterion(timeseriesField, true);
|
||||
expected =
|
||||
"{\n"
|
||||
+ " \"bool\" : {\n"
|
||||
+ " \"should\" : [\n"
|
||||
+ " {\n"
|
||||
+ " \"terms\" : {\n"
|
||||
+ " \"fieldTags\" : [\n"
|
||||
+ " \"value1\",\n"
|
||||
+ " \"value2\"\n"
|
||||
+ " ],\n"
|
||||
+ " \"boost\" : 1.0,\n"
|
||||
+ " \"_name\" : \"fieldTags\"\n"
|
||||
+ " }\n"
|
||||
+ " },\n"
|
||||
+ " {\n"
|
||||
+ " \"terms\" : {\n"
|
||||
+ " \"editedFieldTags\" : [\n"
|
||||
+ " \"value1\",\n"
|
||||
+ " \"value2\"\n"
|
||||
+ " ],\n"
|
||||
+ " \"boost\" : 1.0,\n"
|
||||
+ " \"_name\" : \"editedFieldTags\"\n"
|
||||
+ " }\n"
|
||||
+ " }\n"
|
||||
+ " ],\n"
|
||||
+ " \"adjust_pure_negative\" : true,\n"
|
||||
+ " \"boost\" : 1.0\n"
|
||||
+ " }\n"
|
||||
+ "}";
|
||||
Assert.assertEquals(result.toString(), expected);
|
||||
}
|
||||
}
|
||||
@ -20,11 +20,16 @@ enum Condition {
|
||||
*/
|
||||
EQUAL
|
||||
|
||||
/**
|
||||
/**
|
||||
* Represent the relation: field is null, e.g. platform is null
|
||||
*/
|
||||
IS_NULL
|
||||
|
||||
/**
|
||||
* Represents the relation: field exists and is non-empty, e.g. owners is not null and != [] (empty)
|
||||
*/
|
||||
EXISTS
|
||||
|
||||
/**
|
||||
* Represent the relation greater than, e.g. ownerCount > 5
|
||||
*/
|
||||
|
||||
@ -56,11 +56,12 @@
|
||||
"type" : "enum",
|
||||
"name" : "Condition",
|
||||
"doc" : "The matching condition in a filter criterion",
|
||||
"symbols" : [ "CONTAIN", "END_WITH", "EQUAL", "IS_NULL", "GREATER_THAN", "GREATER_THAN_OR_EQUAL_TO", "IN", "LESS_THAN", "LESS_THAN_OR_EQUAL_TO", "START_WITH" ],
|
||||
"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" ],
|
||||
"symbolDocs" : {
|
||||
"CONTAIN" : "Represent the relation: String field contains value, e.g. name contains Profile",
|
||||
"END_WITH" : "Represent the relation: String field ends with value, e.g. name ends with Event",
|
||||
"EQUAL" : "Represent the relation: field = value, e.g. platform = hdfs",
|
||||
"EXISTS" : "Represents the relation: field exists and is non-empty, e.g. owners is not null and != [] (empty)",
|
||||
"GREATER_THAN" : "Represent the relation greater than, e.g. ownerCount > 5",
|
||||
"GREATER_THAN_OR_EQUAL_TO" : "Represent the relation greater than or equal to, e.g. ownerCount >= 5",
|
||||
"IN" : "Represent the relation: String field is one of the array values to, e.g. name in [\"Profile\", \"Event\"]",
|
||||
|
||||
@ -146,11 +146,12 @@
|
||||
"type" : "enum",
|
||||
"name" : "Condition",
|
||||
"doc" : "The matching condition in a filter criterion",
|
||||
"symbols" : [ "CONTAIN", "END_WITH", "EQUAL", "IS_NULL", "GREATER_THAN", "GREATER_THAN_OR_EQUAL_TO", "IN", "LESS_THAN", "LESS_THAN_OR_EQUAL_TO", "START_WITH" ],
|
||||
"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" ],
|
||||
"symbolDocs" : {
|
||||
"CONTAIN" : "Represent the relation: String field contains value, e.g. name contains Profile",
|
||||
"END_WITH" : "Represent the relation: String field ends with value, e.g. name ends with Event",
|
||||
"EQUAL" : "Represent the relation: field = value, e.g. platform = hdfs",
|
||||
"EXISTS" : "Represents the relation: field exists and is non-empty, e.g. owners is not null and != [] (empty)",
|
||||
"GREATER_THAN" : "Represent the relation greater than, e.g. ownerCount > 5",
|
||||
"GREATER_THAN_OR_EQUAL_TO" : "Represent the relation greater than or equal to, e.g. ownerCount >= 5",
|
||||
"IN" : "Represent the relation: String field is one of the array values to, e.g. name in [\"Profile\", \"Event\"]",
|
||||
|
||||
@ -5637,11 +5637,12 @@
|
||||
"name" : "Condition",
|
||||
"namespace" : "com.linkedin.metadata.query.filter",
|
||||
"doc" : "The matching condition in a filter criterion",
|
||||
"symbols" : [ "CONTAIN", "END_WITH", "EQUAL", "IS_NULL", "GREATER_THAN", "GREATER_THAN_OR_EQUAL_TO", "IN", "LESS_THAN", "LESS_THAN_OR_EQUAL_TO", "START_WITH" ],
|
||||
"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" ],
|
||||
"symbolDocs" : {
|
||||
"CONTAIN" : "Represent the relation: String field contains value, e.g. name contains Profile",
|
||||
"END_WITH" : "Represent the relation: String field ends with value, e.g. name ends with Event",
|
||||
"EQUAL" : "Represent the relation: field = value, e.g. platform = hdfs",
|
||||
"EXISTS" : "Represents the relation: field exists and is non-empty, e.g. owners is not null and != [] (empty)",
|
||||
"GREATER_THAN" : "Represent the relation greater than, e.g. ownerCount > 5",
|
||||
"GREATER_THAN_OR_EQUAL_TO" : "Represent the relation greater than or equal to, e.g. ownerCount >= 5",
|
||||
"IN" : "Represent the relation: String field is one of the array values to, e.g. name in [\"Profile\", \"Event\"]",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user