|
18 | 18 | */ |
19 | 19 | package org.elasticsearch.search.aggregations.metrics.tophits; |
20 | 20 |
|
| 21 | +import org.apache.lucene.analysis.core.KeywordAnalyzer; |
21 | 22 | import org.apache.lucene.document.Document; |
22 | 23 | import org.apache.lucene.document.Field; |
23 | 24 | import org.apache.lucene.document.SortedSetDocValuesField; |
24 | 25 | import org.apache.lucene.index.DirectoryReader; |
25 | 26 | import org.apache.lucene.index.IndexReader; |
26 | 27 | import org.apache.lucene.index.RandomIndexWriter; |
| 28 | +import org.apache.lucene.queryparser.classic.QueryParser; |
27 | 29 | import org.apache.lucene.search.IndexSearcher; |
28 | 30 | import org.apache.lucene.search.MatchAllDocsQuery; |
| 31 | +import org.apache.lucene.search.MatchNoDocsQuery; |
| 32 | +import org.apache.lucene.search.Query; |
29 | 33 | import org.apache.lucene.store.Directory; |
30 | 34 | import org.apache.lucene.util.BytesRef; |
31 | 35 | import org.elasticsearch.index.mapper.KeywordFieldMapper; |
32 | 36 | import org.elasticsearch.index.mapper.MappedFieldType; |
33 | 37 | import org.elasticsearch.index.mapper.Uid; |
34 | 38 | import org.elasticsearch.index.mapper.UidFieldMapper; |
35 | 39 | import org.elasticsearch.search.SearchHits; |
| 40 | +import org.elasticsearch.search.aggregations.Aggregation; |
| 41 | +import org.elasticsearch.search.aggregations.AggregationBuilder; |
36 | 42 | import org.elasticsearch.search.aggregations.AggregatorTestCase; |
| 43 | +import org.elasticsearch.search.aggregations.bucket.terms.Terms; |
37 | 44 | import org.elasticsearch.search.sort.SortOrder; |
38 | 45 |
|
| 46 | +import java.io.IOException; |
| 47 | + |
| 48 | +import static org.elasticsearch.search.aggregations.AggregationBuilders.terms; |
| 49 | +import static org.elasticsearch.search.aggregations.AggregationBuilders.topHits; |
| 50 | + |
39 | 51 | public class TopHitsAggregatorTests extends AggregatorTestCase { |
| 52 | + public void testTopLevel() throws Exception { |
| 53 | + Aggregation result; |
| 54 | + if (randomBoolean()) { |
| 55 | + result = testCase(new MatchAllDocsQuery(), topHits("_name").sort("string", SortOrder.DESC)); |
| 56 | + } else { |
| 57 | + Query query = new QueryParser("string", new KeywordAnalyzer()).parse("d^1000 c^100 b^10 a^1"); |
| 58 | + result = testCase(query, topHits("_name")); |
| 59 | + } |
| 60 | + SearchHits searchHits = ((TopHits) result).getHits(); |
| 61 | + assertEquals(3L, searchHits.getTotalHits()); |
| 62 | + assertEquals("3", searchHits.getAt(0).getId()); |
| 63 | + assertEquals("type", searchHits.getAt(0).getType()); |
| 64 | + assertEquals("2", searchHits.getAt(1).getId()); |
| 65 | + assertEquals("type", searchHits.getAt(1).getType()); |
| 66 | + assertEquals("1", searchHits.getAt(2).getId()); |
| 67 | + assertEquals("type", searchHits.getAt(2).getType()); |
| 68 | + } |
| 69 | + |
| 70 | + public void testNoResults() throws Exception { |
| 71 | + TopHits result = (TopHits) testCase(new MatchNoDocsQuery(), topHits("_name").sort("string", SortOrder.DESC)); |
| 72 | + SearchHits searchHits = ((TopHits) result).getHits(); |
| 73 | + assertEquals(0L, searchHits.getTotalHits()); |
| 74 | + } |
| 75 | + |
| 76 | + /** |
| 77 | + * Tests {@code top_hits} inside of {@code terms}. While not strictly a unit test this is a fairly common way to run {@code top_hits} |
| 78 | + * and serves as a good example of running {@code top_hits} inside of another aggregation. |
| 79 | + */ |
| 80 | + public void testInsideTerms() throws Exception { |
| 81 | + Aggregation result; |
| 82 | + if (randomBoolean()) { |
| 83 | + result = testCase(new MatchAllDocsQuery(), |
| 84 | + terms("term").field("string") |
| 85 | + .subAggregation(topHits("top").sort("string", SortOrder.DESC))); |
| 86 | + } else { |
| 87 | + Query query = new QueryParser("string", new KeywordAnalyzer()).parse("d^1000 c^100 b^10 a^1"); |
| 88 | + result = testCase(query, |
| 89 | + terms("term").field("string") |
| 90 | + .subAggregation(topHits("top"))); |
| 91 | + } |
| 92 | + Terms terms = (Terms) result; |
| 93 | + |
| 94 | + // The "a" bucket |
| 95 | + TopHits hits = (TopHits) terms.getBucketByKey("a").getAggregations().get("top"); |
| 96 | + SearchHits searchHits = (hits).getHits(); |
| 97 | + assertEquals(2L, searchHits.getTotalHits()); |
| 98 | + assertEquals("2", searchHits.getAt(0).getId()); |
| 99 | + assertEquals("1", searchHits.getAt(1).getId()); |
| 100 | + |
| 101 | + // The "b" bucket |
| 102 | + searchHits = ((TopHits) terms.getBucketByKey("b").getAggregations().get("top")).getHits(); |
| 103 | + assertEquals(2L, searchHits.getTotalHits()); |
| 104 | + assertEquals("3", searchHits.getAt(0).getId()); |
| 105 | + assertEquals("1", searchHits.getAt(1).getId()); |
40 | 106 |
|
41 | | - public void testTermsAggregator() throws Exception { |
| 107 | + // The "c" bucket |
| 108 | + searchHits = ((TopHits) terms.getBucketByKey("c").getAggregations().get("top")).getHits(); |
| 109 | + assertEquals(1L, searchHits.getTotalHits()); |
| 110 | + assertEquals("2", searchHits.getAt(0).getId()); |
| 111 | + |
| 112 | + // The "d" bucket |
| 113 | + searchHits = ((TopHits) terms.getBucketByKey("d").getAggregations().get("top")).getHits(); |
| 114 | + assertEquals(1L, searchHits.getTotalHits()); |
| 115 | + assertEquals("3", searchHits.getAt(0).getId()); |
| 116 | + } |
| 117 | + |
| 118 | + private static final MappedFieldType STRING_FIELD_TYPE = new KeywordFieldMapper.KeywordFieldType(); |
| 119 | + static { |
| 120 | + STRING_FIELD_TYPE.setName("string"); |
| 121 | + STRING_FIELD_TYPE.setHasDocValues(true); |
| 122 | + } |
| 123 | + |
| 124 | + private Aggregation testCase(Query query, AggregationBuilder builder) throws IOException { |
42 | 125 | Directory directory = newDirectory(); |
43 | | - RandomIndexWriter indexWriter = new RandomIndexWriter(random(), directory); |
44 | | - Document document = new Document(); |
45 | | - document.add(new Field(UidFieldMapper.NAME, Uid.createUid("type", "1"), UidFieldMapper.Defaults.FIELD_TYPE)); |
46 | | - document.add(new SortedSetDocValuesField("string", new BytesRef("a"))); |
47 | | - document.add(new SortedSetDocValuesField("string", new BytesRef("b"))); |
48 | | - indexWriter.addDocument(document); |
49 | | - document = new Document(); |
50 | | - document.add(new Field(UidFieldMapper.NAME, Uid.createUid("type", "2"), UidFieldMapper.Defaults.FIELD_TYPE)); |
51 | | - document.add(new SortedSetDocValuesField("string", new BytesRef("c"))); |
52 | | - document.add(new SortedSetDocValuesField("string", new BytesRef("a"))); |
53 | | - indexWriter.addDocument(document); |
54 | | - document = new Document(); |
55 | | - document.add(new Field(UidFieldMapper.NAME, Uid.createUid("type", "3"), UidFieldMapper.Defaults.FIELD_TYPE)); |
56 | | - document.add(new SortedSetDocValuesField("string", new BytesRef("b"))); |
57 | | - document.add(new SortedSetDocValuesField("string", new BytesRef("d"))); |
58 | | - indexWriter.addDocument(document); |
59 | | - indexWriter.close(); |
| 126 | + RandomIndexWriter iw = new RandomIndexWriter(random(), directory); |
| 127 | + iw.addDocument(document("1", "a", "b")); |
| 128 | + iw.addDocument(document("2", "c", "a")); |
| 129 | + iw.addDocument(document("3", "b", "d")); |
| 130 | + iw.close(); |
60 | 131 |
|
61 | 132 | IndexReader indexReader = DirectoryReader.open(directory); |
62 | 133 | IndexSearcher indexSearcher = newSearcher(indexReader, true, true); |
63 | 134 |
|
64 | | - MappedFieldType fieldType = new KeywordFieldMapper.KeywordFieldType(); |
65 | | - fieldType.setName("string"); |
66 | | - fieldType.setHasDocValues(true ); |
67 | | - TopHitsAggregationBuilder aggregationBuilder = new TopHitsAggregationBuilder("_name"); |
68 | | - aggregationBuilder.sort("string", SortOrder.DESC); |
69 | | - try (TopHitsAggregator aggregator = createAggregator(aggregationBuilder, indexSearcher, fieldType)){ |
70 | | - aggregator.preCollection(); |
71 | | - indexSearcher.search(new MatchAllDocsQuery(), aggregator); |
72 | | - aggregator.postCollection(); |
73 | | - TopHits topHits = (TopHits) aggregator.buildAggregation(0L); |
74 | | - SearchHits searchHits = topHits.getHits(); |
75 | | - assertEquals(3L, searchHits.getTotalHits()); |
76 | | - assertEquals("3", searchHits.getAt(0).getId()); |
77 | | - assertEquals("type", searchHits.getAt(0).getType()); |
78 | | - assertEquals("2", searchHits.getAt(1).getId()); |
79 | | - assertEquals("type", searchHits.getAt(1).getType()); |
80 | | - assertEquals("1", searchHits.getAt(2).getId()); |
81 | | - assertEquals("type", searchHits.getAt(2).getType()); |
82 | | - } |
| 135 | + Aggregation result = searchAndReduce(indexSearcher, query, builder, STRING_FIELD_TYPE); |
83 | 136 | indexReader.close(); |
84 | 137 | directory.close(); |
| 138 | + return result; |
85 | 139 | } |
86 | 140 |
|
| 141 | + private Document document(String id, String... stringValues) { |
| 142 | + Document document = new Document(); |
| 143 | + document.add(new Field(UidFieldMapper.NAME, Uid.createUid("type", id), UidFieldMapper.Defaults.FIELD_TYPE)); |
| 144 | + for (String stringValue : stringValues) { |
| 145 | + document.add(new Field("string", stringValue, STRING_FIELD_TYPE)); |
| 146 | + document.add(new SortedSetDocValuesField("string", new BytesRef(stringValue))); |
| 147 | + } |
| 148 | + return document; |
| 149 | + } |
87 | 150 | } |
0 commit comments