|
7 | 7 |
|
8 | 8 | package org.elasticsearch.xpack.logsdb.qa; |
9 | 9 |
|
| 10 | +import org.apache.lucene.search.join.ScoreMode; |
10 | 11 | import org.elasticsearch.client.Request; |
11 | 12 | import org.elasticsearch.client.Response; |
12 | 13 | import org.elasticsearch.client.ResponseException; |
13 | 14 | import org.elasticsearch.client.RestClient; |
| 15 | +import org.elasticsearch.common.Strings; |
14 | 16 | import org.elasticsearch.common.settings.Settings; |
15 | 17 | import org.elasticsearch.common.time.DateFormatter; |
16 | 18 | import org.elasticsearch.common.time.FormatNames; |
17 | 19 | import org.elasticsearch.common.xcontent.XContentHelper; |
18 | 20 | import org.elasticsearch.datageneration.matchers.MatchResult; |
19 | 21 | import org.elasticsearch.datageneration.matchers.Matcher; |
| 22 | +import org.elasticsearch.datageneration.matchers.source.SourceTransforms; |
| 23 | +import org.elasticsearch.index.query.MatchPhraseQueryBuilder; |
| 24 | +import org.elasticsearch.index.query.QueryBuilder; |
20 | 25 | import org.elasticsearch.index.query.QueryBuilders; |
| 26 | +import org.elasticsearch.index.similarity.ScriptedSimilarity; |
21 | 27 | import org.elasticsearch.search.aggregations.AggregationBuilders; |
22 | 28 | import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval; |
23 | 29 | import org.elasticsearch.search.aggregations.bucket.histogram.HistogramAggregationBuilder; |
|
34 | 40 | import java.time.ZonedDateTime; |
35 | 41 | import java.time.temporal.ChronoUnit; |
36 | 42 | import java.util.ArrayList; |
| 43 | +import java.util.Arrays; |
37 | 44 | import java.util.Comparator; |
38 | 45 | import java.util.List; |
39 | 46 | import java.util.Map; |
@@ -138,13 +145,81 @@ public void testMatchAllQuery() throws IOException { |
138 | 145 | assertTrue(matchResult.getMessage(), matchResult.isMatch()); |
139 | 146 | } |
140 | 147 |
|
141 | | - public void testTermsQuery() throws IOException { |
| 148 | + private List<String> getFieldsOfType(String type, Map<String, Map<String, Object>> mappingLookup) { |
| 149 | + return mappingLookup.entrySet().stream() |
| 150 | + .filter(e -> { |
| 151 | + var mapping = e.getValue(); |
| 152 | + return mapping != null && type.equals(mapping.get("type")); |
| 153 | + }) |
| 154 | + .map(Map.Entry::getKey) |
| 155 | + .toList(); |
| 156 | + } |
| 157 | + |
| 158 | + private List<String> getSearchableFields(String type, Map<String, Map<String, Object>> mappingLookup) { |
| 159 | + var fields = new ArrayList<String>(); |
| 160 | + for (var e : mappingLookup.entrySet()) { |
| 161 | + var mapping = e.getValue(); |
| 162 | + if (mapping != null && type.equals(mapping.get("type"))) { |
| 163 | + boolean isIndexed = "false".equals(mapping.get("index")) == false; |
| 164 | + boolean hasDocValues = "false".equals(mapping.get("doc_values")) == false; |
| 165 | + if (isIndexed || hasDocValues) { |
| 166 | + fields.add(e.getKey()); |
| 167 | + } |
| 168 | + } |
| 169 | + } |
| 170 | + return fields; |
| 171 | + } |
| 172 | + |
| 173 | + private QueryBuilder nestedPhraseQuery(String path, String phrase) { |
| 174 | + String[] parts = path.split("\\."); |
| 175 | + List<Boolean> nested = dataGenerationHelper.isNested(parts); |
| 176 | + |
| 177 | + QueryBuilder query = QueryBuilders.matchPhraseQuery(path, phrase); |
| 178 | + for (int i = parts.length - 2; i >= 0; i--) { |
| 179 | + if (nested.get(i)) { |
| 180 | + var pathToObject = String.join(".", Arrays.copyOfRange(parts, 0, i + 1)); |
| 181 | + query = QueryBuilders.nestedQuery(pathToObject, query, ScoreMode.Max); |
| 182 | + } |
| 183 | + } |
| 184 | + return query; |
| 185 | + } |
| 186 | + |
| 187 | + public void testPhraseQuery() throws IOException { |
142 | 188 | int numberOfDocuments = ESTestCase.randomIntBetween(20, 80); |
143 | 189 | final List<XContentBuilder> documents = generateDocuments(numberOfDocuments); |
144 | 190 |
|
| 191 | + var mappingLookup = dataGenerationHelper.mapping().lookup(); |
| 192 | + var fieldsOfType = getSearchableFields("keyword", mappingLookup); |
| 193 | + |
| 194 | + if (fieldsOfType.isEmpty()) { |
| 195 | + return; |
| 196 | + } |
| 197 | + |
| 198 | + var field = randomFrom(fieldsOfType); |
| 199 | + |
| 200 | + XContentBuilder doc = randomFrom(documents); |
| 201 | + final Map<String, Object> document = XContentHelper.convertToMap(XContentType.JSON.xContent(), Strings.toString(doc), true); |
| 202 | + var normalized = SourceTransforms.normalize(document, mappingLookup); |
| 203 | + List<Object> values = normalized.get(field); |
| 204 | + if (values == null || values.isEmpty()) { |
| 205 | + return; |
| 206 | + } |
| 207 | + String needle = (String) randomFrom(values); |
| 208 | + var tokens = Arrays.asList(needle.split("[^a-zA-Z0-9]")); |
| 209 | + |
| 210 | + if (tokens.isEmpty()) { |
| 211 | + return; |
| 212 | + } |
| 213 | + |
| 214 | + int low = ESTestCase.randomIntBetween(0, tokens.size() - 1); |
| 215 | + int hi = ESTestCase.randomIntBetween(low+1, tokens.size()); |
| 216 | + var phrase = String.join(" ", tokens.subList(low, hi)); |
| 217 | + System.out.println("phrase: " + phrase); |
| 218 | + |
145 | 219 | indexDocuments(documents); |
146 | 220 |
|
147 | | - final SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder().query(QueryBuilders.termQuery("method", "put")) |
| 221 | + QueryBuilder queryBuilder = nestedPhraseQuery(field, phrase); |
| 222 | + final SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder().query(queryBuilder) |
148 | 223 | .size(numberOfDocuments); |
149 | 224 |
|
150 | 225 | final MatchResult matchResult = Matcher.matchSource() |
|
0 commit comments