Skip to content

Commit dae8a7a

Browse files
authored
chore | adding the support for querying multi interaction filters (#203)
* chore | adding the support for querying multi interaction filters
1 parent 4055aaf commit dae8a7a

File tree

8 files changed

+161
-87
lines changed

8 files changed

+161
-87
lines changed

hypertrace-graphql-entity-schema/src/main/java/org/hypertrace/graphql/entity/dao/GatewayServiceEntityEdgeFetcher.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.slf4j.LoggerFactory;
3131

3232
class GatewayServiceEntityEdgeFetcher {
33+
3334
private static final Logger LOG = LoggerFactory.getLogger(GatewayServiceEntityEdgeFetcher.class);
3435
static final EdgeResultSet EMPTY_EDGE_RESULT_SET = new ConvertedEdgeResultSet(List.of());
3536

@@ -119,16 +120,22 @@ private Maybe<Edge> buildEdge(
119120

120121
return zip(
121122
this.attributeMapConverter.convert(
122-
edgeSetGroupRequest.attributeRequests(), response.getAttributeMap()),
123+
edgeSetGroupRequest.edgeSetRequests().get(neighbor.type()).attributeRequests(),
124+
response.getAttributeMap()),
123125
this.baselineMetricAggregationContainerMapConverter.convert(
124-
edgeSetGroupRequest.metricAggregationRequests(), response.getMetricsMap()),
126+
edgeSetGroupRequest
127+
.edgeSetRequests()
128+
.get(neighbor.type())
129+
.metricAggregationRequests(),
130+
response.getMetricsMap()),
125131
(attributes, metrics) -> (Edge) new ConvertedEdge(neighbor, attributes, metrics))
126132
.toMaybe();
127133
}
128134

129135
@lombok.Value
130136
@Accessors(fluent = true)
131137
private static class ConvertedEdge implements Edge {
138+
132139
Entity neighbor;
133140
Map<AttributeExpression, Object> attributeValues;
134141
Map<AttributeExpression, BaselinedMetricAggregationContainer> metricContainers;
@@ -147,6 +154,7 @@ public BaselinedMetricAggregationContainer metric(AttributeExpression attributeE
147154
@lombok.Value
148155
@Accessors(fluent = true)
149156
private static class ConvertedEdgeResultSet implements EdgeResultSet {
157+
150158
List<Edge> results;
151159

152160
@Override

hypertrace-graphql-entity-schema/src/main/java/org/hypertrace/graphql/entity/dao/GatewayServiceEntityInteractionRequestBuilder.java

Lines changed: 46 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,10 @@
2121
import org.hypertrace.core.graphql.common.utils.Converter;
2222
import org.hypertrace.gateway.service.v1.common.Expression;
2323
import org.hypertrace.gateway.service.v1.common.Filter;
24+
import org.hypertrace.gateway.service.v1.common.Operator;
2425
import org.hypertrace.gateway.service.v1.entity.InteractionsRequest;
2526
import org.hypertrace.graphql.entity.request.EdgeSetGroupRequest;
27+
import org.hypertrace.graphql.entity.request.EdgeSetRequest;
2628
import org.hypertrace.graphql.metric.request.MetricAggregationRequest;
2729

2830
class GatewayServiceEntityInteractionRequestBuilder {
@@ -44,7 +46,7 @@ class GatewayServiceEntityInteractionRequestBuilder {
4446
}
4547

4648
Single<InteractionsRequest> build(EdgeSetGroupRequest edgeSetRequestGroup) {
47-
if (edgeSetRequestGroup.entityTypes().isEmpty()) {
49+
if (edgeSetRequestGroup.edgeSetRequests().isEmpty()) {
4850
return Single.just(InteractionsRequest.getDefaultInstance());
4951
}
5052

@@ -61,40 +63,64 @@ Single<InteractionsRequest> build(EdgeSetGroupRequest edgeSetRequestGroup) {
6163

6264
private Single<Set<Expression>> collectSelectionsAndAggregations(EdgeSetGroupRequest request) {
6365
return this.selectionConverter
64-
.convert(request.attributeRequests())
65-
.mergeWith(this.aggregationConverter.convert(request.metricAggregationRequests()))
66+
.convert(getAllAttributeRequests(request))
67+
.mergeWith(this.aggregationConverter.convert(getAllMetricAggregationRequests(request)))
6668
.toObservable()
6769
.flatMap(Observable::fromIterable)
6870
.collect(Collectors.toUnmodifiableSet());
6971
}
7072

73+
private Set<AttributeRequest> getAllAttributeRequests(EdgeSetGroupRequest request) {
74+
return request.edgeSetRequests().values().stream()
75+
.map(EdgeSetRequest::attributeRequests)
76+
.flatMap(Collection::stream)
77+
.collect(Collectors.toUnmodifiableSet());
78+
}
79+
80+
private Set<MetricAggregationRequest> getAllMetricAggregationRequests(
81+
EdgeSetGroupRequest request) {
82+
return request.edgeSetRequests().values().stream()
83+
.map(EdgeSetRequest::metricAggregationRequests)
84+
.flatMap(Collection::stream)
85+
.collect(Collectors.toUnmodifiableSet());
86+
}
87+
7188
private Single<Filter> buildEntityInteractionFilter(EdgeSetGroupRequest request) {
72-
return Observable.fromIterable(request.entityTypes()) // add entity types filter
73-
.collect(Collectors.toUnmodifiableSet())
89+
// Todo: we should be using converter taking argument as logical filters with filter arg schema
90+
return Observable.fromIterable(request.edgeSetRequests().entrySet())
91+
.map(
92+
entry ->
93+
Stream.concat(
94+
Stream.of(buildEntityTypeFilter(request, entry.getKey())),
95+
entry.getValue().filterArguments().stream())
96+
.collect(Collectors.toUnmodifiableList()))
97+
.flatMapSingle(this.filterConverter::convert)
98+
.collect(Collectors.toUnmodifiableList())
7499
.map(
75-
entityTypes ->
76-
AttributeAssociation.<FilterArgument>of(
77-
request.neighborTypeAttribute().attributeExpressionAssociation().attribute(),
78-
new EntityNeighborTypeFilter(
79-
request.neighborTypeAttribute().attributeExpressionAssociation().value(),
80-
entityTypes)))
81-
.flatMap(
82-
filterAssociation ->
83-
this.filterConverter.convert(
84-
Stream.concat(
85-
request.filterArguments().stream(), // add all other filters
86-
Stream.of(filterAssociation))
87-
.collect(Collectors.toUnmodifiableSet())));
100+
childFilters ->
101+
Filter.newBuilder()
102+
.setOperator(Operator.OR)
103+
.addAllChildFilter(childFilters)
104+
.build());
105+
}
106+
107+
private AttributeAssociation<FilterArgument> buildEntityTypeFilter(
108+
EdgeSetGroupRequest request, String entityType) {
109+
return AttributeAssociation.of(
110+
request.neighborTypeAttribute().attributeExpressionAssociation().attribute(),
111+
new EntityNeighborTypeFilter(
112+
request.neighborTypeAttribute().attributeExpressionAssociation().value(), entityType));
88113
}
89114

90115
@Value
91116
@Accessors(fluent = true)
92117
private static class EntityNeighborTypeFilter implements FilterArgument {
118+
93119
FilterType type = FilterType.ATTRIBUTE;
94120
String key = null;
95121
AttributeExpression keyExpression;
96-
FilterOperatorType operator = FilterOperatorType.IN;
97-
Collection<String> value;
122+
FilterOperatorType operator = FilterOperatorType.EQUALS;
123+
String value;
98124
AttributeScope idType = null;
99125
String idScope = null;
100126
}

hypertrace-graphql-entity-schema/src/main/java/org/hypertrace/graphql/entity/joiner/DefaultEntityJoinerBuilder.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,14 @@
5252
import org.hypertrace.core.graphql.utils.schema.SelectionQuery;
5353
import org.hypertrace.graphql.entity.dao.EntityDao;
5454
import org.hypertrace.graphql.entity.request.EdgeSetGroupRequest;
55+
import org.hypertrace.graphql.entity.request.EdgeSetRequest;
5556
import org.hypertrace.graphql.entity.request.EntityLabelRequest;
5657
import org.hypertrace.graphql.entity.request.EntityLabelRequestBuilder;
5758
import org.hypertrace.graphql.entity.request.EntityRequest;
5859
import org.hypertrace.graphql.entity.schema.Entity;
5960
import org.hypertrace.graphql.entity.schema.EntityJoinable;
6061
import org.hypertrace.graphql.entity.schema.EntityResultSet;
6162
import org.hypertrace.graphql.entity.schema.argument.EntityTypeStringArgument;
62-
import org.hypertrace.graphql.metric.request.MetricAggregationRequest;
6363
import org.hypertrace.graphql.metric.request.MetricRequest;
6464
import org.hypertrace.graphql.metric.request.MetricRequestBuilder;
6565
import org.hypertrace.graphql.metric.schema.argument.AggregatableOrderArgument;
@@ -317,12 +317,9 @@ private static class DefaultEntityRequest implements EntityRequest {
317317
@Value
318318
@Accessors(fluent = true)
319319
private static class EmptyEdgeSetGroupRequest implements EdgeSetGroupRequest {
320-
Set<String> entityTypes = Collections.emptySet();
321-
Collection<AttributeRequest> attributeRequests = Collections.emptyList();
322-
Collection<MetricAggregationRequest> metricAggregationRequests = Collections.emptyList();
323-
Collection<AttributeAssociation<FilterArgument>> filterArguments = Collections.emptyList();
324320
AttributeRequest neighborIdAttribute = null;
325321
AttributeRequest neighborTypeAttribute = null;
322+
Map<String, EdgeSetRequest> edgeSetRequests = Collections.emptyMap();
326323

327324
@Override
328325
public Single<EntityRequest> buildNeighborRequest(

hypertrace-graphql-entity-schema/src/main/java/org/hypertrace/graphql/entity/request/EdgeRequestBuilder.java

Lines changed: 81 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33
import static io.reactivex.rxjava3.core.Single.zip;
44

55
import graphql.schema.SelectedField;
6-
import io.grpc.Status;
6+
import io.reactivex.rxjava3.core.Observable;
77
import io.reactivex.rxjava3.core.Single;
88
import java.util.Collection;
99
import java.util.List;
1010
import java.util.Map;
11+
import java.util.Map.Entry;
1112
import java.util.Optional;
1213
import java.util.Set;
1314
import java.util.function.BiFunction;
@@ -89,35 +90,18 @@ private Single<EdgeSetGroupRequest> buildEdgeRequest(
8990
Stream<SelectedField> edgeSetFields,
9091
EdgeType edgeType) {
9192
Set<SelectedField> edgeFields = edgeSetFields.collect(Collectors.toUnmodifiableSet());
92-
List<FilterArgument> filterArguments = this.getFilters(edgeFields);
93-
94-
if (!filterArguments.isEmpty() && edgeFields.size() > 1) {
95-
throw Status.UNIMPLEMENTED
96-
.withDescription("Cannot specify more than one edge type with edge filters")
97-
.asRuntimeException();
98-
}
99-
100-
Map<String, Set<SelectedField>> edgesByType = this.getEdgesByType(edgeFields.stream());
101-
Set<SelectedField> allEdges =
102-
edgesByType.values().stream()
103-
.flatMap(Collection::stream)
104-
.collect(Collectors.toUnmodifiableSet());
93+
Map<String, Set<SelectedField>> edgesSelectionsByType =
94+
this.getEdgesSelectionByType(edgeFields.stream());
10595

10696
return zip(
107-
this.getRequestedAndRequiredAttributes(context, allEdges, edgeType),
10897
this.getNeighborIdAttribute(context, edgeType),
10998
this.getNeighborTypeAttribute(context, edgeType),
110-
this.metricAggregationRequestBuilder.build(
111-
context, HypertraceAttributeScopeString.INTERACTION, allEdges.stream()),
112-
this.filterRequestBuilder.build(
113-
context, HypertraceAttributeScopeString.INTERACTION, filterArguments),
114-
(attributeRequests, neighborIdRequest, neighborTypeRequest, metricRequests, filters) ->
99+
this.getEntityTypeToEdgeSetRequest(context, edgeType, edgeFields),
100+
(neighborIdRequest, neighborTypeRequest, edgeRequests) ->
115101
new DefaultEdgeSetGroupRequest(
116-
edgesByType.keySet(),
117-
attributeRequests,
118-
metricRequests,
119102
neighborIdRequest,
120103
neighborTypeRequest,
104+
edgeRequests,
121105
(entityType, neighborIds) ->
122106
this.neighborEntitiesRequestBuilderProvider
123107
.get()
@@ -127,12 +111,44 @@ private Single<EdgeSetGroupRequest> buildEdgeRequest(
127111
timeRange,
128112
space,
129113
neighborIds,
130-
edgesByType.get(entityType)),
131-
filters));
114+
edgesSelectionsByType.get(entityType))));
115+
}
116+
117+
private Single<Map<String, EdgeSetRequest>> getEntityTypeToEdgeSetRequest(
118+
GraphQlRequestContext context, EdgeType edgeType, Set<SelectedField> edgeFields) {
119+
return Observable.fromIterable(edgeFields)
120+
.collect(Collectors.groupingBy(this::getEntityType, Collectors.toUnmodifiableSet()))
121+
.flatMap(edgeFieldsMap -> this.getEdgeSetRequestMap(context, edgeType, edgeFieldsMap));
132122
}
133123

134-
private Map<String, Set<SelectedField>> getEdgesByType(Stream<SelectedField> edgeSetStream) {
124+
private Single<Map<String, EdgeSetRequest>> getEdgeSetRequestMap(
125+
GraphQlRequestContext context,
126+
EdgeType edgeType,
127+
Map<String, Set<SelectedField>> entityTypeToEdgeFieldsMap) {
128+
return Observable.fromIterable(entityTypeToEdgeFieldsMap.entrySet())
129+
.flatMapSingle(
130+
entry ->
131+
this.getEdgeSetRequestEntry(context, edgeType, entry.getKey(), entry.getValue()))
132+
.collect(Collectors.toUnmodifiableMap(Entry::getKey, Entry::getValue));
133+
}
135134

135+
private Single<Map.Entry<String, EdgeSetRequest>> getEdgeSetRequestEntry(
136+
GraphQlRequestContext context,
137+
EdgeType edgeType,
138+
String entityType,
139+
Set<SelectedField> edgeFields) {
140+
return zip(
141+
this.getRequestedAndRequiredAttributes(context, edgeFields, edgeType),
142+
this.getMetricAggregationRequestAttributes(context, edgeFields),
143+
this.getFilterArguments(context, edgeFields),
144+
(requestAttributes, metricAttributes, filters) ->
145+
Map.entry(
146+
entityType,
147+
new DefaultEdgeSetRequest(requestAttributes, metricAttributes, filters)));
148+
}
149+
150+
private Map<String, Set<SelectedField>> getEdgesSelectionByType(
151+
Stream<SelectedField> edgeSetStream) {
136152
return edgeSetStream.collect(
137153
Collectors.groupingBy(
138154
this::getEntityType,
@@ -155,11 +171,25 @@ private String getEntityType(SelectedField edgeSetField) {
155171
.orElseThrow();
156172
}
157173

174+
private Single<List<MetricAggregationRequest>> getMetricAggregationRequestAttributes(
175+
GraphQlRequestContext context, Collection<SelectedField> edges) {
176+
Set<SelectedField> selections =
177+
edges.stream()
178+
.collect(
179+
Collectors.flatMapping(this::getEdgesForEdgeSet, Collectors.toUnmodifiableSet()));
180+
return this.metricAggregationRequestBuilder.build(
181+
context, HypertraceAttributeScopeString.INTERACTION, selections.stream());
182+
}
183+
158184
private Single<List<AttributeRequest>> getRequestedAndRequiredAttributes(
159185
GraphQlRequestContext context, Collection<SelectedField> edges, EdgeType edgeType) {
186+
Set<SelectedField> selections =
187+
edges.stream()
188+
.collect(
189+
Collectors.flatMapping(this::getEdgesForEdgeSet, Collectors.toUnmodifiableSet()));
160190
return this.attributeRequestBuilder
161191
.buildForAttributeQueryableFields(
162-
context, HypertraceAttributeScopeString.INTERACTION, edges.stream())
192+
context, HypertraceAttributeScopeString.INTERACTION, selections.stream())
163193
.mergeWith(this.getNeighborIdAttribute(context, edgeType))
164194
.mergeWith(this.getNeighborTypeAttribute(context, edgeType))
165195
.collect(Collectors.toUnmodifiableList());
@@ -183,15 +213,21 @@ private Single<AttributeRequest> getNeighborIdAttribute(
183213
}
184214
}
185215

186-
private List<FilterArgument> getFilters(Set<SelectedField> selectedFields) {
187-
return selectedFields.stream()
188-
.map(
189-
selectedField ->
190-
this.argumentDeserializer.deserializeObjectList(
191-
selectedField.getArguments(), FilterArgument.class))
192-
.flatMap(Optional::stream)
193-
.flatMap(Collection::stream)
194-
.collect(Collectors.toUnmodifiableList());
216+
private Single<List<AttributeAssociation<FilterArgument>>> getFilterArguments(
217+
GraphQlRequestContext context, Set<SelectedField> edgeFields) {
218+
Set<FilterArgument> filterArguments =
219+
edgeFields.stream()
220+
.collect(Collectors.flatMapping(this::getFilter, Collectors.toUnmodifiableSet()));
221+
222+
return this.filterRequestBuilder.build(
223+
context, HypertraceAttributeScopeString.INTERACTION, filterArguments);
224+
}
225+
226+
private Stream<FilterArgument> getFilter(SelectedField selectedField) {
227+
return this.argumentDeserializer
228+
.deserializeObjectList(selectedField.getArguments(), FilterArgument.class)
229+
.stream()
230+
.flatMap(Collection::stream);
195231
}
196232

197233
private Single<AttributeRequest> getNeighborTypeAttribute(
@@ -220,19 +256,23 @@ private enum EdgeType {
220256
@Value
221257
@Accessors(fluent = true)
222258
private static class DefaultEdgeSetGroupRequest implements EdgeSetGroupRequest {
223-
224-
Set<String> entityTypes;
225-
Collection<AttributeRequest> attributeRequests;
226-
Collection<MetricAggregationRequest> metricAggregationRequests;
227259
AttributeRequest neighborIdAttribute;
228260
AttributeRequest neighborTypeAttribute;
261+
Map<String, EdgeSetRequest> edgeSetRequests;
229262
BiFunction<String, Collection<String>, Single<EntityRequest>> neighborRequestBuilder;
230-
Collection<AttributeAssociation<FilterArgument>> filterArguments;
231263

232264
@Override
233265
public Single<EntityRequest> buildNeighborRequest(
234266
String entityType, Collection<String> neighborIds) {
235267
return this.neighborRequestBuilder.apply(entityType, neighborIds);
236268
}
237269
}
270+
271+
@Value
272+
@Accessors(fluent = true)
273+
private static class DefaultEdgeSetRequest implements EdgeSetRequest {
274+
Collection<AttributeRequest> attributeRequests;
275+
Collection<MetricAggregationRequest> metricAggregationRequests;
276+
Collection<AttributeAssociation<FilterArgument>> filterArguments;
277+
}
238278
}

hypertrace-graphql-entity-schema/src/main/java/org/hypertrace/graphql/entity/request/EdgeSetGroupRequest.java

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,15 @@
22

33
import io.reactivex.rxjava3.core.Single;
44
import java.util.Collection;
5-
import java.util.Set;
6-
import org.hypertrace.core.graphql.common.request.AttributeAssociation;
5+
import java.util.Map;
76
import org.hypertrace.core.graphql.common.request.AttributeRequest;
8-
import org.hypertrace.core.graphql.common.schema.results.arguments.filter.FilterArgument;
9-
import org.hypertrace.graphql.metric.request.MetricAggregationRequest;
107

118
public interface EdgeSetGroupRequest {
12-
13-
Set<String> entityTypes();
14-
15-
// Includes neighbor id and type
16-
Collection<AttributeRequest> attributeRequests();
17-
18-
Collection<MetricAggregationRequest> metricAggregationRequests();
19-
209
AttributeRequest neighborIdAttribute();
2110

2211
AttributeRequest neighborTypeAttribute();
2312

2413
Single<EntityRequest> buildNeighborRequest(String entityType, Collection<String> neighborIds);
2514

26-
Collection<AttributeAssociation<FilterArgument>> filterArguments();
15+
Map<String, EdgeSetRequest> edgeSetRequests();
2716
}

0 commit comments

Comments
 (0)