@@ -4,76 +4,99 @@ import (
4
4
"encoding/json"
5
5
)
6
6
7
+ // ExportElasticSearchQuery exports the compiled query into an ElasticSearch query, e.g.
8
+ // `"foo" OR "baz"` will be compiled to
9
+ // {"bool":{"should":[{"wildcard":{"raw":{"case_insensitive":false,"value":"foo"}}},{"wildcard":{"raw":{"case_insensitive":false,"value":"bar"}}}]}}
7
10
func (e * Evalostic ) ExportElasticSearchQuery (wildcardField string ) string {
8
11
indexToStrings := make (map [int ]string )
9
12
for k , v := range e .strings {
10
13
indexToStrings [v ] = k
11
14
}
12
- query := e .exportElasticSearchQuery (wildcardField , indexToStrings , decisionTreeEntry {value : - 1 }, e .decisionTree )
15
+ query := e .exportElasticSearchQuerySub (wildcardField , indexToStrings , decisionTreeEntry {value : - 1 }, e .decisionTree )
13
16
if query == nil {
14
17
return ""
15
18
}
16
19
b , _ := json .Marshal (query )
17
20
return string (b )
18
21
}
19
22
20
- func (e * Evalostic ) exportElasticSearchQuery (wildcardField string , indexToStrings map [int ]string , entry decisionTreeEntry , node * decisionTreeNode ) interface {} {
21
- var must []interface {}
22
- var mustNot []interface {}
23
- for entry , node := range node .children {
24
- subQuery := e .exportElasticSearchQuery (wildcardField , indexToStrings , entry , node )
25
- if subQuery != nil {
26
- must = append (must , subQuery )
27
- }
28
- }
29
- for entry , node := range node .notChildren {
30
- subQuery := e .exportElasticSearchQuery (wildcardField , indexToStrings , entry , node )
31
- if subQuery != nil {
32
- mustNot = append (mustNot , subQuery )
33
- }
34
- }
35
- var wildcard interface {}
36
- if entry .value != - 1 {
37
- wildcard = map [string ]interface {}{
38
- "wildcard" : map [string ]interface {}{
39
- wildcardField : map [string ]interface {}{
40
- "value" : indexToStrings [entry .value ],
41
- "case_insensitive" : entry .ci ,
42
- },
23
+ func (e * Evalostic ) exportElasticSearchQuerySub (wildcardField string , indexToStrings map [int ]string , entry decisionTreeEntry , node * decisionTreeNode ) interface {} {
24
+
25
+ type Map map [string ]interface {}
26
+
27
+ isLeaf := len (node .outputs ) != 0
28
+ wildcard := Map {
29
+ "wildcard" : Map {
30
+ wildcardField : Map {
31
+ "value" : indexToStrings [entry .value ],
32
+ "case_insensitive" : entry .ci ,
43
33
},
44
- }
34
+ },
45
35
}
46
- if len (node .outputs ) != 0 {
36
+ if entry .value == - 1 {
37
+ // special case: do not use root node as wildcard
38
+ wildcard = nil
39
+ }
40
+ if isLeaf && wildcard != nil {
41
+ // special case: if it's a leaf, we don't need to process the sub tree
47
42
return wildcard
48
43
}
49
- if len (must ) == 0 && len (mustNot ) == 0 {
50
- return nil
44
+
45
+ var should , shouldNot []interface {}
46
+
47
+ for subEntry , subNode := range node .children {
48
+ if subQuery := e .exportElasticSearchQuerySub (wildcardField , indexToStrings , subEntry , subNode ); subQuery != nil {
49
+ should = append (should , subQuery )
50
+ }
51
51
}
52
- boolRes := make (map [string ]interface {})
53
- if len (must ) != 0 {
54
- boolRes ["should" ] = must
52
+ for subEntry , subNode := range node .notChildren {
53
+ if subQuery := e .exportElasticSearchQuerySub (wildcardField , indexToStrings , subEntry , subNode ); subQuery != nil {
54
+ shouldNot = append (shouldNot , subQuery )
55
+ }
55
56
}
56
- if len (mustNot ) != 0 {
57
- if len (mustNot ) == 1 {
58
- boolRes ["must_not" ] = mustNot
57
+
58
+ toQuery := func (should []interface {}, not bool ) interface {} {
59
+ if len (should ) == 0 {
60
+ return nil
61
+ }
62
+ var res interface {}
63
+ if len (should ) == 1 {
64
+ res = should [0 ]
59
65
} else {
60
- boolRes ["must_not" ] = map [string ]interface {}{
61
- "bool" : map [string ]interface {}{
62
- "should" : mustNot ,
66
+ res = Map {
67
+ "bool" : Map {
68
+ "should" : should ,
69
+ },
70
+ }
71
+ }
72
+ if not {
73
+ // wrap OR conditions with a NOT
74
+ res = Map {
75
+ "bool" : Map {
76
+ "must_not" : []interface {}{res },
63
77
},
64
78
}
65
79
}
80
+ return res
81
+ }
82
+
83
+ notChildQuery := toQuery (shouldNot , true )
84
+ if notChildQuery != nil {
85
+ should = append (should , notChildQuery )
86
+ }
87
+ childQuery := toQuery (should , false )
88
+ if childQuery == nil {
89
+ return nil
66
90
}
67
91
if wildcard == nil {
68
- return map [ string ] interface {}{ "bool" : boolRes }
92
+ return childQuery
69
93
}
70
- res := map [ string ] interface {} {
71
- "bool" : map [ string ] interface {} {
94
+ return Map {
95
+ "bool" : Map {
72
96
"must" : []interface {}{
73
97
wildcard ,
74
- map [ string ] interface {}{ "bool" : boolRes } ,
98
+ childQuery ,
75
99
},
76
100
},
77
101
}
78
- return res
79
102
}
0 commit comments