Skip to content
This repository was archived by the owner on Jun 26, 2024. It is now read-only.

Commit af6e8b0

Browse files
authored
fix | fix the entity ids filter for explore if empty (#197)
* fix | fix the entity ids filter for explore if empty
1 parent f284959 commit af6e8b0

2 files changed

Lines changed: 105 additions & 50 deletions

File tree

gateway-service-impl/src/main/java/org/hypertrace/gateway/service/explore/RequestHandler.java

Lines changed: 105 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import com.google.common.collect.Streams;
66
import com.google.protobuf.InvalidProtocolBufferException;
77
import com.google.protobuf.util.JsonFormat;
8-
import java.util.ArrayList;
8+
import io.grpc.Status;
99
import java.util.Collections;
1010
import java.util.Iterator;
1111
import java.util.List;
@@ -35,10 +35,14 @@
3535
import org.hypertrace.gateway.service.entity.EntitiesRequestContext;
3636
import org.hypertrace.gateway.service.entity.config.EntityIdColumnsConfig;
3737
import org.hypertrace.gateway.service.explore.entity.EntityServiceEntityFetcher;
38+
import org.hypertrace.gateway.service.v1.common.AttributeExpression;
3839
import org.hypertrace.gateway.service.v1.common.Expression;
3940
import org.hypertrace.gateway.service.v1.common.FunctionExpression;
41+
import org.hypertrace.gateway.service.v1.common.LiteralConstant;
42+
import org.hypertrace.gateway.service.v1.common.Operator;
4043
import org.hypertrace.gateway.service.v1.common.OrderByExpression;
4144
import org.hypertrace.gateway.service.v1.common.TimeAggregation;
45+
import org.hypertrace.gateway.service.v1.common.ValueType;
4246
import org.hypertrace.gateway.service.v1.entity.EntitiesRequest;
4347
import org.hypertrace.gateway.service.v1.entity.Entity.Builder;
4448
import org.hypertrace.gateway.service.v1.explore.ExploreRequest;
@@ -63,6 +67,17 @@
6367
*/
6468
public class RequestHandler implements RequestHandlerWithSorting {
6569
private static final Logger LOG = LoggerFactory.getLogger(RequestHandler.class);
70+
private static final Expression NULL_VALUE_EXPRESSION =
71+
Expression.newBuilder()
72+
.setLiteral(
73+
LiteralConstant.newBuilder()
74+
.setValue(
75+
org.hypertrace.gateway.service.v1.common.Value.newBuilder()
76+
.setValueType(ValueType.STRING)
77+
.setString("null")
78+
.build())
79+
.build())
80+
.build();
6681

6782
private final QueryServiceClient queryServiceClient;
6883
private final AttributeMetadataProvider attributeMetadataProvider;
@@ -107,15 +122,30 @@ QueryRequest buildQueryRequest(
107122
requestContext.setHasGroupBy(true);
108123
}
109124

110-
List<String> entityIds = new ArrayList<>();
111125
org.hypertrace.gateway.service.v1.common.Filter qsSourceFilter = request.getFilter();
112126
Map<String, AttributeMetadata> attributeMetadataMap =
113127
attributeMetadataProvider.getAttributesMetadata(requestContext, request.getContext());
114128
if (hasOnlyAttributeSource(request.getFilter(), AttributeSource.EDS, attributeMetadataMap)) {
115-
entityIds = getEntityIdsToFilterFromSourceEDS(requestContext, request, attributeMetadataMap);
129+
List<String> entityIds =
130+
getEntityIdsToFilterFromSourceEDS(requestContext, request, attributeMetadataMap);
131+
List<String> entityIdAttributes =
132+
AttributeMetadataUtil.getIdAttributeIds(
133+
attributeMetadataProvider,
134+
entityIdColumnsConfig,
135+
requestContext,
136+
request.getContext());
116137
qsSourceFilter =
117-
buildFilter(request.getFilter(), AttributeSource.QS, attributeMetadataMap)
118-
.orElse(request.getFilter());
138+
org.hypertrace.gateway.service.v1.common.Filter.newBuilder()
139+
.setOperator(Operator.AND)
140+
.addChildFilter(
141+
buildFilter(request.getFilter(), AttributeSource.QS, attributeMetadataMap)
142+
.orElse(request.getFilter()))
143+
.addChildFilter(
144+
createEntityIdAttributeFilter(
145+
entityIdAttributes,
146+
org.hypertrace.gateway.service.v1.common.Operator.IN,
147+
entityIds))
148+
.build();
119149
}
120150

121151
QueryRequest.Builder builder = QueryRequest.newBuilder();
@@ -141,7 +171,7 @@ QueryRequest buildQueryRequest(
141171
// 2. Add filter
142172
builder.setFilter(
143173
constructQueryServiceFilter(
144-
request, qsSourceFilter, requestContext, attributeMetadataProvider, entityIds));
174+
request, qsSourceFilter, requestContext, attributeMetadataProvider));
145175

146176
if (requestContext.hasGroupBy() && request.getIncludeRestGroup() && request.getOffset() > 0) {
147177
// including rest group with offset is an invalid combination
@@ -280,33 +310,22 @@ Filter constructQueryServiceFilter(
280310
ExploreRequestContext exploreRequestContext,
281311
AttributeMetadataProvider attributeMetadataProvider) {
282312
return this.constructQueryServiceFilter(
283-
request,
284-
request.getFilter(),
285-
exploreRequestContext,
286-
attributeMetadataProvider,
287-
Collections.emptyList());
313+
request, request.getFilter(), exploreRequestContext, attributeMetadataProvider);
288314
}
289315

290316
Filter constructQueryServiceFilter(
291317
ExploreRequest request,
292318
org.hypertrace.gateway.service.v1.common.Filter requestFilter,
293319
ExploreRequestContext exploreRequestContext,
294-
AttributeMetadataProvider attributeMetadataProvider,
295-
List<String> entityIds) {
296-
return QueryAndGatewayDtoConverter.addTimeSpaceAndIdFiltersAndConvertToQueryFilter(
320+
AttributeMetadataProvider attributeMetadataProvider) {
321+
return QueryAndGatewayDtoConverter.addTimeAndSpaceFiltersAndConvertToQueryFilter(
297322
request.getStartTimeMillis(),
298323
request.getEndTimeMillis(),
299324
request.getSpaceId(),
300-
entityIds,
301325
AttributeMetadataUtil.getTimestampAttributeId(
302326
attributeMetadataProvider, exploreRequestContext, request.getContext()),
303327
AttributeMetadataUtil.getSpaceAttributeId(
304328
attributeMetadataProvider, exploreRequestContext, request.getContext()),
305-
AttributeMetadataUtil.getIdAttributeIds(
306-
attributeMetadataProvider,
307-
entityIdColumnsConfig,
308-
exploreRequestContext,
309-
request.getContext()),
310329
requestFilter);
311330
}
312331

@@ -532,6 +551,72 @@ private Map<String, AttributeMetadata> remapAttributeMetadataByResultName(
532551
attributeMetadataByIdMap);
533552
}
534553

554+
private org.hypertrace.gateway.service.v1.common.Filter createEntityIdAttributeFilter(
555+
List<String> entityIdAttributes,
556+
org.hypertrace.gateway.service.v1.common.Operator operator,
557+
List<String> entityIds) {
558+
if (entityIdAttributes.size() != 1) {
559+
throw Status.FAILED_PRECONDITION
560+
.withDescription("entity must have one id attribute.")
561+
.asRuntimeException();
562+
}
563+
564+
if (entityIds.isEmpty()) {
565+
// TODO: have a better approach here. One possible solution could be to
566+
// form a dummy response based on the selections provided
567+
568+
// Having empty entity ids is valid filter because this means that
569+
// EDS source has filtered out all the entities and the result should
570+
// be empty. But QS doesn't recognize empty IN filter as valid filter
571+
// and ignoring this filter will generate wrong results.
572+
//
573+
// We could have return empty but clients expects response to contain
574+
// information as per the selections they have sent. So we are converting
575+
// empty entity Id filter into a false filter (id != null && id == null)
576+
// so that results are always empty but must contain the valid selections.
577+
return org.hypertrace.gateway.service.v1.common.Filter.newBuilder()
578+
.setOperator(Operator.AND)
579+
.addChildFilter(
580+
org.hypertrace.gateway.service.v1.common.Filter.newBuilder()
581+
.setLhs(buildAttributeExpression(entityIdAttributes.get(0)))
582+
.setOperator(Operator.EQ)
583+
.setRhs(NULL_VALUE_EXPRESSION)
584+
.build())
585+
.addChildFilter(
586+
org.hypertrace.gateway.service.v1.common.Filter.newBuilder()
587+
.setLhs(buildAttributeExpression(entityIdAttributes.get(0)))
588+
.setOperator(Operator.NEQ)
589+
.setRhs(NULL_VALUE_EXPRESSION)
590+
.build())
591+
.build();
592+
}
593+
594+
return org.hypertrace.gateway.service.v1.common.Filter.newBuilder()
595+
.setLhs(buildAttributeExpression(entityIdAttributes.get(0)))
596+
.setOperator(operator)
597+
.setRhs(buildStringArrayExpression(entityIds))
598+
.build();
599+
}
600+
601+
private Expression buildStringArrayExpression(List<String> values) {
602+
return Expression.newBuilder()
603+
.setLiteral(
604+
LiteralConstant.newBuilder()
605+
.setValue(
606+
org.hypertrace.gateway.service.v1.common.Value.newBuilder()
607+
.setValueType(ValueType.STRING_ARRAY)
608+
.addAllStringArray(values)
609+
.build())
610+
.build())
611+
.build();
612+
}
613+
614+
private Expression buildAttributeExpression(String value) {
615+
return Expression.newBuilder()
616+
.setAttributeExpression(AttributeExpression.newBuilder().setAttributeId(value).build())
617+
.build();
618+
}
619+
535620
private boolean hasOnlyAttributeSource(
536621
org.hypertrace.gateway.service.v1.common.Filter filter,
537622
AttributeSource source,

gateway-service-impl/src/test/java/org/hypertrace/gateway/service/explore/RequestHandlerTest.java

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -639,36 +639,6 @@ private QueryRequest getQueryRequest() throws InvalidProtocolBufferException {
639639
+ " \"filter\": {\n"
640640
+ " \"childFilter\": [{\n"
641641
+ " \"childFilter\": [{\n"
642-
+ " \"lhs\": {\n"
643-
+ " \"attributeExpression\": {\n"
644-
+ " \"attributeId\": \"API.timestampId\"\n"
645-
+ " }\n"
646-
+ " },\n"
647-
+ " \"operator\": \"GE\",\n"
648-
+ " \"rhs\": {\n"
649-
+ " \"literal\": {\n"
650-
+ " \"value\": {\n"
651-
+ " \"valueType\": \"LONG\"\n"
652-
+ " }\n"
653-
+ " }\n"
654-
+ " }\n"
655-
+ " }, {\n"
656-
+ " \"lhs\": {\n"
657-
+ " \"attributeExpression\": {\n"
658-
+ " \"attributeId\": \"API.timestampId\"\n"
659-
+ " }\n"
660-
+ " },\n"
661-
+ " \"operator\": \"LT\",\n"
662-
+ " \"rhs\": {\n"
663-
+ " \"literal\": {\n"
664-
+ " \"value\": {\n"
665-
+ " \"valueType\": \"LONG\"\n"
666-
+ " }\n"
667-
+ " }\n"
668-
+ " }\n"
669-
+ " }]\n"
670-
+ " }, {\n"
671-
+ " \"childFilter\": [{\n"
672642
+ " \"childFilter\": [{\n"
673643
+ " \"childFilter\": [{\n"
674644
+ " \"lhs\": {\n"

0 commit comments

Comments
 (0)