3
3
import static com .google .common .collect .ImmutableList .copyOf ;
4
4
import static com .google .common .collect .Iterables .concat ;
5
5
import static org .hypertrace .core .graphql .atttributes .scopes .HypertraceCoreAttributeScopeString .SPAN ;
6
+ import static org .hypertrace .core .graphql .span .joiner .MultipleSpanJoin .SPANS_KEY ;
6
7
import static org .hypertrace .core .graphql .span .joiner .SpanJoin .SPAN_KEY ;
7
8
9
+ import com .google .common .collect .ImmutableListMultimap ;
10
+ import com .google .common .collect .ListMultimap ;
8
11
import graphql .schema .DataFetchingFieldSelectionSet ;
9
12
import graphql .schema .SelectedField ;
10
13
import io .reactivex .rxjava3 .core .Observable ;
46
49
public class DefaultSpanJoinerBuilder implements SpanJoinerBuilder {
47
50
48
51
private static final int ZERO_OFFSET = 0 ;
49
-
50
52
private final SpanDao spanDao ;
51
53
private final GraphQlSelectionFinder selectionFinder ;
54
+
52
55
private final ResultSetRequestBuilder resultSetRequestBuilder ;
53
56
private final FilterRequestBuilder filterRequestBuilder ;
54
57
@@ -70,61 +73,100 @@ public Single<SpanJoiner> build(
70
73
TimeRangeArgument timeRange ,
71
74
DataFetchingFieldSelectionSet selectionSet ,
72
75
List <String > pathToSpanJoin ) {
73
- return Single .just (
74
- new DefaultSpanJoiner (
75
- context , timeRange , this .getSelections (selectionSet , pathToSpanJoin )));
76
- }
77
-
78
- private List <SelectedField > getSelections (
79
- DataFetchingFieldSelectionSet selectionSet , List <String > pathToSpanJoin ) {
80
- List <String > fullPath = copyOf (concat (pathToSpanJoin , List .of (SPAN_KEY )));
81
- return selectionFinder
82
- .findSelections (selectionSet , SelectionQuery .builder ().selectionPath (fullPath ).build ())
83
- .collect (Collectors .toUnmodifiableList ());
76
+ return Single .just (new DefaultSpanJoiner (context , timeRange , selectionSet , pathToSpanJoin ));
84
77
}
85
78
86
79
@ AllArgsConstructor
87
80
private class DefaultSpanJoiner implements SpanJoiner {
88
81
89
82
private final GraphQlRequestContext context ;
90
83
private final TimeRangeArgument timeRange ;
91
- private final List <SelectedField > selectedFields ;
84
+ private final DataFetchingFieldSelectionSet selectionSet ;
85
+ private final List <String > pathToJoin ;
92
86
93
87
@ Override
94
- public <T > Single <Map <T , Span >> joinSpans (
88
+ public <T > Single <Map <T , Span >> joinSpan (
95
89
Collection <T > joinSources , SpanIdGetter <T > spanIdGetter ) {
96
- return this .buildSourceToIdMap (joinSources , spanIdGetter ).flatMap (this ::joinSpans );
90
+ Function <T , Single <List <String >>> idsGetter =
91
+ source -> spanIdGetter .getSpanId (source ).map (List ::of );
92
+ return this .joinSpans (joinSources , idsGetter , SPAN_KEY ).map (this ::reduceMap );
97
93
}
98
94
99
- private <T > Single <Map <T , Span >> joinSpans (Map <T , String > sourceToSpanIdMap ) {
100
- return this .buildSpanRequest (sourceToSpanIdMap )
101
- .flatMap (spanDao ::getSpans )
102
- .map (this ::buildSpanIdToSpanMap )
103
- .map (spanIdToSpanMap -> buildSourceToSpanMap (sourceToSpanIdMap , spanIdToSpanMap ));
95
+ @ Override
96
+ public <T > Single <ListMultimap <T , Span >> joinSpans (
97
+ Collection <T > joinSources , MultipleSpanIdGetter <T > multipleSpanIdGetter ) {
98
+ return this .joinSpans (joinSources , multipleSpanIdGetter ::getSpanIds , SPANS_KEY );
104
99
}
105
100
106
- private <T > Map <T , Span > buildSourceToSpanMap (
107
- Map <T , String > sourceToSpanIdMap , Map <String , Span > spanIdToSpanMap ) {
108
- return sourceToSpanIdMap .entrySet ().stream ()
109
- .filter (entry -> spanIdToSpanMap .containsKey (entry .getValue ()))
101
+ private <T > Single <ListMultimap <T , Span >> joinSpans (
102
+ Collection <T > joinSources ,
103
+ Function <T , Single <List <String >>> idsGetter ,
104
+ String joinSpanKey ) {
105
+ return this .buildSourceToIdsMap (joinSources , idsGetter )
106
+ .flatMap (
107
+ sourceToSpanIdsMap ->
108
+ this .buildSpanRequest (sourceToSpanIdsMap , joinSpanKey )
109
+ .flatMap (spanDao ::getSpans )
110
+ .map (this ::buildSpanIdToSpanMap )
111
+ .map (
112
+ spanIdToSpanMap ->
113
+ this .buildSourceToSpanListMultiMap (
114
+ sourceToSpanIdsMap , spanIdToSpanMap )));
115
+ }
116
+
117
+ private <T > Map <T , Span > reduceMap (ListMultimap <T , Span > listMultimap ) {
118
+ return listMultimap .entries ().stream ()
110
119
.collect (
111
120
Collectors .toUnmodifiableMap (
121
+ Entry ::getKey , Entry ::getValue , (first , second ) -> first ));
122
+ }
123
+
124
+ private <T > Single <ImmutableListMultimap <T , String >> buildSourceToIdsMap (
125
+ Collection <T > joinSources , Function <T , Single <List <String >>> idsGetter ) {
126
+ return Observable .fromIterable (joinSources )
127
+ .flatMapSingle (source -> idsGetter .apply (source ).map (ids -> Map .entry (source , ids )))
128
+ .collect (
129
+ ImmutableListMultimap .flatteningToImmutableListMultimap (
130
+ Entry ::getKey , entry -> entry .getValue ().stream ()));
131
+ }
132
+
133
+ private <T > ImmutableListMultimap <T , Span > buildSourceToSpanListMultiMap (
134
+ ListMultimap <T , String > sourceToSpanIdsMultimap , Map <String , Span > spanIdToSpanMap ) {
135
+ return sourceToSpanIdsMultimap .entries ().stream ()
136
+ .filter (entry -> spanIdToSpanMap .containsKey (entry .getValue ()))
137
+ .collect (
138
+ ImmutableListMultimap .toImmutableListMultimap (
112
139
Entry ::getKey , entry -> spanIdToSpanMap .get (entry .getValue ())));
113
140
}
114
141
142
+ private List <SelectedField > getSelections (String joinSpanKey ) {
143
+ List <String > fullPath = copyOf (concat (pathToJoin , List .of (joinSpanKey )));
144
+ return selectionFinder
145
+ .findSelections (selectionSet , SelectionQuery .builder ().selectionPath (fullPath ).build ())
146
+ .collect (Collectors .toUnmodifiableList ());
147
+ }
148
+
115
149
private Map <String , Span > buildSpanIdToSpanMap (SpanResultSet resultSet ) {
116
150
return resultSet .results ().stream ()
117
151
.collect (Collectors .toUnmodifiableMap (Identifiable ::id , Function .identity ()));
118
152
}
119
153
120
- private <T > Single <SpanRequest > buildSpanRequest (Map <T , String > sourceToSpanIdMap ) {
121
- Collection <String > spanIds = sourceToSpanIdMap .values ();
122
- return buildSpanIdsFilter (spanIds )
123
- .flatMap (filterArguments -> buildSpanRequest (spanIds .size (), filterArguments ));
154
+ private <T > Single <SpanRequest > buildSpanRequest (
155
+ ListMultimap <T , String > sourceToSpanIdsMultimap , String joinSpanKey ) {
156
+ Collection <String > spanIds =
157
+ sourceToSpanIdsMultimap .values ().stream ()
158
+ .distinct ()
159
+ .collect (Collectors .toUnmodifiableList ());
160
+ List <SelectedField > selectedFields = getSelections (joinSpanKey );
161
+ return buildSpanIdsFilter (context , spanIds )
162
+ .flatMap (
163
+ filterArguments -> buildSpanRequest (spanIds .size (), filterArguments , selectedFields ));
124
164
}
125
165
126
166
private Single <SpanRequest > buildSpanRequest (
127
- int size , List <AttributeAssociation <FilterArgument >> filterArguments ) {
167
+ int size ,
168
+ List <AttributeAssociation <FilterArgument >> filterArguments ,
169
+ List <SelectedField > selectedFields ) {
128
170
return resultSetRequestBuilder
129
171
.build (
130
172
context ,
@@ -140,21 +182,9 @@ private Single<SpanRequest> buildSpanRequest(
140
182
}
141
183
142
184
private Single <List <AttributeAssociation <FilterArgument >>> buildSpanIdsFilter (
143
- Collection <String > spanIds ) {
185
+ GraphQlRequestContext context , Collection <String > spanIds ) {
144
186
return filterRequestBuilder .build (context , SPAN , Set .of (new SpanIdFilter (spanIds )));
145
187
}
146
-
147
- private <T > Single <Map <T , String >> buildSourceToIdMap (
148
- Collection <T > joinSources , SpanIdGetter <T > spanIdGetter ) {
149
- return Observable .fromIterable (joinSources )
150
- .flatMapSingle (source -> this .maybeBuildMapEntry (source , spanIdGetter ))
151
- .collect (Collectors .toMap (Entry ::getKey , Entry ::getValue ));
152
- }
153
-
154
- private <T > Single <Entry <T , String >> maybeBuildMapEntry (
155
- T source , SpanIdGetter <T > spanIdGetter ) {
156
- return spanIdGetter .getSpanId (source ).map (id -> Map .entry (source , id ));
157
- }
158
188
}
159
189
160
190
@ Value
0 commit comments