1
1
package org .elasticsearch .plugin .nlpcn .executors ;
2
2
3
+ import com .sun .org .apache .xpath .internal .operations .Mult ;
4
+ import org .elasticsearch .cluster .routing .allocation .decider .Decision ;
5
+ import org .elasticsearch .common .base .Joiner ;
3
6
import org .elasticsearch .search .SearchHit ;
4
7
import org .elasticsearch .search .SearchHits ;
8
+ import org .elasticsearch .search .aggregations .Aggregation ;
9
+ import org .elasticsearch .search .aggregations .AggregationBuilder ;
10
+ import org .elasticsearch .search .aggregations .Aggregations ;
11
+ import org .elasticsearch .search .aggregations .bucket .MultiBucketsAggregation ;
12
+ import org .elasticsearch .search .aggregations .bucket .SingleBucketAggregation ;
13
+ import org .elasticsearch .search .aggregations .bucket .geogrid .GeoHashGrid ;
14
+ import org .elasticsearch .search .aggregations .metrics .MetricsAggregator ;
15
+ import org .elasticsearch .search .aggregations .metrics .NumericMetricsAggregation ;
16
+ import org .elasticsearch .search .aggregations .metrics .scripted .ScriptedMetric ;
17
+ import org .elasticsearch .search .aggregations .metrics .stats .extended .ExtendedStats ;
5
18
6
19
import java .util .*;
7
20
8
21
/**
9
22
* Created by Eliran on 27/12/2015.
10
23
*/
11
24
public class CSVResultsExtractor {
12
- public static CSVResult extractResults (Object queryResult , boolean flat , String separator ) {
25
+ private int currentLineIndex ;
26
+
27
+ public CSVResultsExtractor () {
28
+ this .currentLineIndex = 0 ;
29
+ }
30
+
31
+ public CSVResult extractResults (Object queryResult , boolean flat , String separator ) {
13
32
if (queryResult instanceof SearchHits ){
14
33
SearchHit [] hits = ((SearchHits ) queryResult ).getHits ();
15
- Set <String > csvHeaders = new HashSet <>();
16
34
List <Map <String ,Object >> docsAsMap = new ArrayList <>();
17
- for (SearchHit hit : hits ){
18
- Map <String , Object > doc = hit .sourceAsMap ();
19
- mergeHeaders (csvHeaders ,doc ,flat );
20
- docsAsMap .add (doc );
21
- }
22
- List <String > headers = new ArrayList <>(csvHeaders );
35
+ List <String > headers = createHeadersAndFillDocsMap (flat , hits , docsAsMap );
36
+ List <String > csvLines = createCSVLinesFromDocs (flat , separator , docsAsMap , headers );
37
+ return new CSVResult (headers ,csvLines );
38
+ }
39
+ if (queryResult instanceof Aggregations ){
40
+ List <String > headers = new ArrayList <>();
41
+ List <List <String >> lines = new ArrayList <>();
42
+ lines .add (new ArrayList <String >());
43
+ handleAggregations ((Aggregations ) queryResult , headers , lines );
23
44
24
- List <String > csvLines = new ArrayList <>();
25
- for (Map <String ,Object > doc : docsAsMap ){
26
- String line = "" ;
27
- for (String header : headers ){
28
- line += findFieldValue (header , doc , flat , separator );
29
- }
30
- csvLines .add (line .substring (0 , line .length () - 1 ));
45
+ List <String > csvLines = new ArrayList <>();
46
+ for (List <String > simpleLine : lines ){
47
+ csvLines .add (Joiner .on (separator ).join (simpleLine ));
31
48
}
32
49
50
+ //todo: need to handle more options for aggregations:
51
+ //NumericMetricsAggregation.Multi : ExtendedStats,Stats,Percentiles
52
+ //Aggregations that inhrit from base
53
+ //ScriptedMetric
54
+ //TopHits
55
+ //GeoBounds
56
+
33
57
return new CSVResult (headers ,csvLines );
58
+
34
59
}
35
60
return null ;
36
61
}
37
62
38
- private static String findFieldValue (String header , Map <String , Object > doc , boolean flat , String separator ) {
63
+ private void handleAggregations (Aggregations aggregations , List <String > headers , List <List <String >> lines ) {
64
+ if (allNumericAggregations (aggregations )){
65
+ lines .get (this .currentLineIndex ).addAll (fillHeaderAndCreateLineForNumericAggregations (aggregations , headers ));
66
+ return ;
67
+ }
68
+ //aggregations with size one only supported when not metrics.
69
+ List <Aggregation > aggregationList = aggregations .asList ();
70
+ if (aggregationList .size () > 1 ){
71
+ //todo: throw exception
72
+ }
73
+ Aggregation aggregation = aggregationList .get (0 );
74
+ //we want to skip singleBucketAggregations (nested,reverse_nested,filters)
75
+ if (aggregation instanceof SingleBucketAggregation ){
76
+ Aggregations singleBucketAggs = ((SingleBucketAggregation ) aggregation ).getAggregations ();
77
+ handleAggregations (singleBucketAggs ,headers ,lines );
78
+ return ;
79
+ }
80
+ if (aggregation instanceof NumericMetricsAggregation ){
81
+ handleNumericMetricAggregation (headers ,lines .get (currentLineIndex ),aggregation );
82
+ return ;
83
+ }
84
+ if (aggregation instanceof MultiBucketsAggregation ){
85
+ MultiBucketsAggregation bucketsAggregation = (MultiBucketsAggregation ) aggregation ;
86
+ String name = bucketsAggregation .getName ();
87
+ //checking because it can comes from sub aggregation again
88
+ if (!headers .contains (name )){
89
+ headers .add (name );
90
+ }
91
+ Collection <? extends MultiBucketsAggregation .Bucket > buckets = bucketsAggregation .getBuckets ();
92
+
93
+ //clone current line.
94
+ List <String > currentLine = lines .get (this .currentLineIndex );
95
+ List <String > clonedLine = new ArrayList <>(currentLine );
96
+
97
+ //call handle_Agg with current_line++
98
+ boolean firstLine = true ;
99
+ for (MultiBucketsAggregation .Bucket bucket : buckets ) {
100
+ //each bucket need to add new line with current line copied => except for first line
101
+ String key = bucket .getKeyAsText ().string ();
102
+ if (firstLine ){
103
+ firstLine = false ;
104
+ }
105
+ else {
106
+ currentLineIndex ++;
107
+ currentLine = new ArrayList <String >(clonedLine );
108
+ lines .add (currentLine );
109
+ }
110
+ currentLine .add (key );
111
+ handleAggregations (bucket .getAggregations (),headers ,lines );
112
+
113
+ }
114
+ }
115
+
116
+ }
117
+
118
+ private List <String > fillHeaderAndCreateLineForNumericAggregations (Aggregations aggregations , List <String > header ) {
119
+ List <String > line = new ArrayList <>();
120
+ List <Aggregation > aggregationList = aggregations .asList ();
121
+ for (Aggregation aggregation : aggregationList ){
122
+ handleNumericMetricAggregation (header , line , aggregation );
123
+ }
124
+ return line ;
125
+ }
126
+
127
+ private void handleNumericMetricAggregation (List <String > header , List <String > line , Aggregation aggregation ) {
128
+ String name = aggregation .getName ();
129
+ if (!header .contains (name )){
130
+ header .add (aggregation .getName ());
131
+ }
132
+ if (aggregation instanceof NumericMetricsAggregation .SingleValue ){
133
+ line .add (((NumericMetricsAggregation .SingleValue ) aggregation ).getValueAsString ());
134
+ }
135
+ //todo:Numeric MultiValue - Stats,ExtendedStats,Percentile...
136
+ else {
137
+
138
+ }
139
+ }
140
+
141
+ private boolean allNumericAggregations (Aggregations aggregations ) {
142
+ List <Aggregation > aggregationList = aggregations .asList ();
143
+ for (Aggregation aggregation : aggregationList ){
144
+ if (!(aggregation instanceof NumericMetricsAggregation )){
145
+ return false ;
146
+ }
147
+ }
148
+ return true ;
149
+ }
150
+
151
+ private Aggregation skipAggregations (Aggregation firstAggregation ) {
152
+ while (firstAggregation instanceof SingleBucketAggregation ){
153
+ firstAggregation = getFirstAggregation (((SingleBucketAggregation ) firstAggregation ).getAggregations ());
154
+ }
155
+ return firstAggregation ;
156
+ }
157
+
158
+ private Aggregation getFirstAggregation (Aggregations aggregations ){
159
+ return aggregations .asList ().get (0 );
160
+ }
161
+
162
+ private List <String > createCSVLinesFromDocs (boolean flat , String separator , List <Map <String , Object >> docsAsMap , List <String > headers ) {
163
+ List <String > csvLines = new ArrayList <>();
164
+ for (Map <String ,Object > doc : docsAsMap ){
165
+ String line = "" ;
166
+ for (String header : headers ){
167
+ line += findFieldValue (header , doc , flat , separator );
168
+ }
169
+ csvLines .add (line .substring (0 , line .length () - 1 ));
170
+ }
171
+ return csvLines ;
172
+ }
173
+
174
+ private List <String > createHeadersAndFillDocsMap (boolean flat , SearchHit [] hits , List <Map <String , Object >> docsAsMap ) {
175
+ Set <String > csvHeaders = new HashSet <>();
176
+ for (SearchHit hit : hits ){
177
+ Map <String , Object > doc = hit .sourceAsMap ();
178
+ mergeHeaders (csvHeaders ,doc ,flat );
179
+ docsAsMap .add (doc );
180
+ }
181
+ return new ArrayList <>(csvHeaders );
182
+ }
183
+
184
+ private String findFieldValue (String header , Map <String , Object > doc , boolean flat , String separator ) {
39
185
if (flat && header .contains ("." )){
40
186
String [] split = header .split ("\\ ." );
41
187
Object innerDoc = doc ;
@@ -59,15 +205,15 @@ private static String findFieldValue(String header, Map<String, Object> doc, boo
59
205
return separator ;
60
206
}
61
207
62
- private static void mergeHeaders (Set <String > headers , Map <String , Object > doc , boolean flat ) {
208
+ private void mergeHeaders (Set <String > headers , Map <String , Object > doc , boolean flat ) {
63
209
if (!flat ) {
64
210
headers .addAll (doc .keySet ());
65
211
return ;
66
212
}
67
213
mergeFieldNamesRecursive (headers , doc , "" );
68
214
}
69
215
70
- private static void mergeFieldNamesRecursive (Set <String > headers , Map <String , Object > doc , String prefix ) {
216
+ private void mergeFieldNamesRecursive (Set <String > headers , Map <String , Object > doc , String prefix ) {
71
217
for (Map .Entry <String ,Object > field : doc .entrySet ()){
72
218
Object value = field .getValue ();
73
219
if (value instanceof Map ){
0 commit comments