Skip to content

Commit fe89ea1

Browse files
committed
percolator: fix handling of nested documents
Nested documents were indexed as separate documents, but it was never checked if the hits represent nested documents or not. Therefore, nested objects could match not nested queries and nested queries could also match not nested documents. Examples are in issue elastic#6540 . closes elastic#6540 closes elastic#6544
1 parent 69350dc commit fe89ea1

File tree

3 files changed

+203
-37
lines changed

3 files changed

+203
-37
lines changed

src/main/java/org/elasticsearch/percolator/PercolatorService.java

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
import org.elasticsearch.index.mapper.internal.IdFieldMapper;
6969
import org.elasticsearch.index.percolator.stats.ShardPercolateService;
7070
import org.elasticsearch.index.query.ParsedQuery;
71+
import org.elasticsearch.index.search.nested.NonNestedDocsFilter;
7172
import org.elasticsearch.index.service.IndexService;
7273
import org.elasticsearch.index.shard.service.IndexShard;
7374
import org.elasticsearch.indices.IndicesService;
@@ -210,8 +211,9 @@ public PercolateShardResponse percolate(PercolateShardRequest request) {
210211

211212
// parse the source either into one MemoryIndex, if it is a single document or index multiple docs if nested
212213
PercolatorIndex percolatorIndex;
214+
boolean isNested = indexShard.mapperService().documentMapper(request.documentType()).hasNestedObjects();
213215
if (parsedDocument.docs().size() > 1) {
214-
assert indexShard.mapperService().documentMapper(request.documentType()).hasNestedObjects();
216+
assert isNested;
215217
percolatorIndex = multi;
216218
} else {
217219
percolatorIndex = single;
@@ -232,7 +234,7 @@ public PercolateShardResponse percolate(PercolateShardRequest request) {
232234
context.percolatorTypeId = action.id();
233235

234236
percolatorIndex.prepare(context, parsedDocument);
235-
return action.doPercolate(request, context);
237+
return action.doPercolate(request, context, isNested);
236238
} finally {
237239
context.close();
238240
shardPercolateService.postPercolate(System.nanoTime() - startTime);
@@ -418,7 +420,7 @@ interface PercolatorType {
418420

419421
ReduceResult reduce(List<PercolateShardResponse> shardResults);
420422

421-
PercolateShardResponse doPercolate(PercolateShardRequest request, PercolateContext context);
423+
PercolateShardResponse doPercolate(PercolateShardRequest request, PercolateContext context, boolean isNested);
422424

423425
}
424426

@@ -443,13 +445,17 @@ public ReduceResult reduce(List<PercolateShardResponse> shardResults) {
443445
}
444446

445447
@Override
446-
public PercolateShardResponse doPercolate(PercolateShardRequest request, PercolateContext context) {
448+
public PercolateShardResponse doPercolate(PercolateShardRequest request, PercolateContext context, boolean isNested) {
447449
long count = 0;
448450
Lucene.ExistsCollector collector = new Lucene.ExistsCollector();
449451
for (Map.Entry<BytesRef, Query> entry : context.percolateQueries().entrySet()) {
450452
collector.reset();
451453
try {
452-
context.docSearcher().search(entry.getValue(), collector);
454+
if (isNested) {
455+
context.docSearcher().search(entry.getValue(), NonNestedDocsFilter.INSTANCE, collector);
456+
} else {
457+
context.docSearcher().search(entry.getValue(), collector);
458+
}
453459
} catch (Throwable e) {
454460
logger.debug("[" + entry.getKey() + "] failed to execute query", e);
455461
throw new PercolateException(context.indexShard().shardId(), "failed to execute", e);
@@ -477,11 +483,11 @@ public ReduceResult reduce(List<PercolateShardResponse> shardResults) {
477483
}
478484

479485
@Override
480-
public PercolateShardResponse doPercolate(PercolateShardRequest request, PercolateContext context) {
486+
public PercolateShardResponse doPercolate(PercolateShardRequest request, PercolateContext context, boolean isNested) {
481487
long count = 0;
482488
Engine.Searcher percolatorSearcher = context.indexShard().acquireSearcher("percolate");
483489
try {
484-
Count countCollector = count(logger, context);
490+
Count countCollector = count(logger, context, isNested);
485491
queryBasedPercolating(percolatorSearcher, context, countCollector);
486492
count = countCollector.counter();
487493
} catch (Throwable e) {
@@ -534,7 +540,7 @@ public ReduceResult reduce(List<PercolateShardResponse> shardResults) {
534540
}
535541

536542
@Override
537-
public PercolateShardResponse doPercolate(PercolateShardRequest request, PercolateContext context) {
543+
public PercolateShardResponse doPercolate(PercolateShardRequest request, PercolateContext context, boolean isNested) {
538544
long count = 0;
539545
List<BytesRef> matches = new ArrayList<>();
540546
List<Map<String, HighlightField>> hls = new ArrayList<>();
@@ -547,7 +553,11 @@ public PercolateShardResponse doPercolate(PercolateShardRequest request, Percola
547553
context.hitContext().cache().clear();
548554
}
549555
try {
550-
context.docSearcher().search(entry.getValue(), collector);
556+
if (isNested) {
557+
context.docSearcher().search(entry.getValue(), NonNestedDocsFilter.INSTANCE, collector);
558+
} else {
559+
context.docSearcher().search(entry.getValue(), collector);
560+
}
551561
} catch (Throwable e) {
552562
logger.debug("[" + entry.getKey() + "] failed to execute query", e);
553563
throw new PercolateException(context.indexShard().shardId(), "failed to execute", e);
@@ -583,10 +593,10 @@ public ReduceResult reduce(List<PercolateShardResponse> shardResults) {
583593
}
584594

585595
@Override
586-
public PercolateShardResponse doPercolate(PercolateShardRequest request, PercolateContext context) {
596+
public PercolateShardResponse doPercolate(PercolateShardRequest request, PercolateContext context, boolean isNested) {
587597
Engine.Searcher percolatorSearcher = context.indexShard().acquireSearcher("percolate");
588598
try {
589-
Match match = match(logger, context, highlightPhase);
599+
Match match = match(logger, context, highlightPhase, isNested);
590600
queryBasedPercolating(percolatorSearcher, context, match);
591601
List<BytesRef> matches = match.matches();
592602
List<Map<String, HighlightField>> hls = match.hls();
@@ -616,10 +626,10 @@ public ReduceResult reduce(List<PercolateShardResponse> shardResults) {
616626
}
617627

618628
@Override
619-
public PercolateShardResponse doPercolate(PercolateShardRequest request, PercolateContext context) {
629+
public PercolateShardResponse doPercolate(PercolateShardRequest request, PercolateContext context, boolean isNested) {
620630
Engine.Searcher percolatorSearcher = context.indexShard().acquireSearcher("percolate");
621631
try {
622-
MatchAndScore matchAndScore = matchAndScore(logger, context, highlightPhase);
632+
MatchAndScore matchAndScore = matchAndScore(logger, context, highlightPhase, isNested);
623633
queryBasedPercolating(percolatorSearcher, context, matchAndScore);
624634
List<BytesRef> matches = matchAndScore.matches();
625635
List<Map<String, HighlightField>> hls = matchAndScore.hls();
@@ -730,10 +740,10 @@ public ReduceResult reduce(List<PercolateShardResponse> shardResults) {
730740
}
731741

732742
@Override
733-
public PercolateShardResponse doPercolate(PercolateShardRequest request, PercolateContext context) {
743+
public PercolateShardResponse doPercolate(PercolateShardRequest request, PercolateContext context, boolean isNested) {
734744
Engine.Searcher percolatorSearcher = context.indexShard().acquireSearcher("percolate");
735745
try {
736-
MatchAndSort matchAndSort = QueryCollector.matchAndSort(logger, context);
746+
MatchAndSort matchAndSort = QueryCollector.matchAndSort(logger, context, isNested);
737747
queryBasedPercolating(percolatorSearcher, context, matchAndSort);
738748
TopDocs topDocs = matchAndSort.topDocs();
739749
long count = topDocs.totalHits;
@@ -785,7 +795,6 @@ private void queryBasedPercolating(Engine.Searcher percolatorSearcher, Percolate
785795
percolatorTypeFilter = context.indexService().cache().filter().cache(percolatorTypeFilter);
786796
XFilteredQuery query = new XFilteredQuery(context.percolateQuery(), percolatorTypeFilter);
787797
percolatorSearcher.searcher().search(query, percolateCollector);
788-
789798
for (Collector queryCollector : percolateCollector.facetAndAggregatorCollector) {
790799
if (queryCollector instanceof XCollector) {
791800
((XCollector) queryCollector).postCollection();

src/main/java/org/elasticsearch/percolator/QueryCollector.java

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.elasticsearch.index.mapper.FieldMapper;
3333
import org.elasticsearch.index.mapper.internal.IdFieldMapper;
3434
import org.elasticsearch.index.query.ParsedQuery;
35+
import org.elasticsearch.index.search.nested.NonNestedDocsFilter;
3536
import org.elasticsearch.search.aggregations.AggregationPhase;
3637
import org.elasticsearch.search.aggregations.Aggregator;
3738
import org.elasticsearch.search.aggregations.bucket.global.GlobalAggregator;
@@ -55,6 +56,7 @@ abstract class QueryCollector extends Collector {
5556
final IndexSearcher searcher;
5657
final ConcurrentMap<BytesRef, Query> queries;
5758
final ESLogger logger;
59+
boolean isNestedDoc = false;
5860

5961
final Lucene.ExistsCollector collector = new Lucene.ExistsCollector();
6062
BytesRef current;
@@ -63,12 +65,13 @@ abstract class QueryCollector extends Collector {
6365

6466
final List<Collector> facetAndAggregatorCollector;
6567

66-
QueryCollector(ESLogger logger, PercolateContext context) {
68+
QueryCollector(ESLogger logger, PercolateContext context, boolean isNestedDoc) {
6769
this.logger = logger;
6870
this.queries = context.percolateQueries();
6971
this.searcher = context.docSearcher();
7072
final FieldMapper<?> idMapper = context.mapperService().smartNameFieldMapper(IdFieldMapper.NAME);
7173
this.idFieldData = context.fieldData().getForField(idMapper);
74+
this.isNestedDoc = isNestedDoc;
7275

7376
ImmutableList.Builder<Collector> facetAggCollectorBuilder = ImmutableList.builder();
7477
if (context.facets() != null) {
@@ -139,20 +142,20 @@ public boolean acceptsDocsOutOfOrder() {
139142
}
140143

141144

142-
static Match match(ESLogger logger, PercolateContext context, HighlightPhase highlightPhase) {
143-
return new Match(logger, context, highlightPhase);
145+
static Match match(ESLogger logger, PercolateContext context, HighlightPhase highlightPhase, boolean isNestedDoc) {
146+
return new Match(logger, context, highlightPhase, isNestedDoc);
144147
}
145148

146-
static Count count(ESLogger logger, PercolateContext context) {
147-
return new Count(logger, context);
149+
static Count count(ESLogger logger, PercolateContext context, boolean isNestedDoc) {
150+
return new Count(logger, context, isNestedDoc);
148151
}
149152

150-
static MatchAndScore matchAndScore(ESLogger logger, PercolateContext context, HighlightPhase highlightPhase) {
151-
return new MatchAndScore(logger, context, highlightPhase);
153+
static MatchAndScore matchAndScore(ESLogger logger, PercolateContext context, HighlightPhase highlightPhase, boolean isNestedDoc) {
154+
return new MatchAndScore(logger, context, highlightPhase, isNestedDoc);
152155
}
153156

154-
static MatchAndSort matchAndSort(ESLogger logger, PercolateContext context) {
155-
return new MatchAndSort(logger, context);
157+
static MatchAndSort matchAndSort(ESLogger logger, PercolateContext context, boolean isNestedDoc) {
158+
return new MatchAndSort(logger, context, isNestedDoc);
156159
}
157160

158161

@@ -179,8 +182,8 @@ final static class Match extends QueryCollector {
179182
final int size;
180183
long counter = 0;
181184

182-
Match(ESLogger logger, PercolateContext context, HighlightPhase highlightPhase) {
183-
super(logger, context);
185+
Match(ESLogger logger, PercolateContext context, HighlightPhase highlightPhase, boolean isNestedDoc) {
186+
super(logger, context, isNestedDoc);
184187
this.limit = context.limit;
185188
this.size = context.size();
186189
this.context = context;
@@ -202,7 +205,11 @@ public void collect(int doc) throws IOException {
202205
context.hitContext().cache().clear();
203206
}
204207

205-
searcher.search(query, collector);
208+
if (isNestedDoc) {
209+
searcher.search(query, NonNestedDocsFilter.INSTANCE, collector);
210+
} else {
211+
searcher.search(query, collector);
212+
}
206213
if (collector.exists()) {
207214
if (!limit || counter < size) {
208215
matches.add(values.copyShared());
@@ -236,8 +243,8 @@ final static class MatchAndSort extends QueryCollector {
236243

237244
private final TopScoreDocCollector topDocsCollector;
238245

239-
MatchAndSort(ESLogger logger, PercolateContext context) {
240-
super(logger, context);
246+
MatchAndSort(ESLogger logger, PercolateContext context, boolean isNestedDoc) {
247+
super(logger, context, isNestedDoc);
241248
// TODO: Use TopFieldCollector.create(...) for ascending and decending scoring?
242249
topDocsCollector = TopScoreDocCollector.create(context.size(), false);
243250
}
@@ -252,7 +259,11 @@ public void collect(int doc) throws IOException {
252259
// run the query
253260
try {
254261
collector.reset();
255-
searcher.search(query, collector);
262+
if (isNestedDoc) {
263+
searcher.search(query, NonNestedDocsFilter.INSTANCE, collector);
264+
} else {
265+
searcher.search(query, collector);
266+
}
256267
if (collector.exists()) {
257268
topDocsCollector.collect(doc);
258269
postMatch(doc);
@@ -294,8 +305,8 @@ final static class MatchAndScore extends QueryCollector {
294305

295306
private Scorer scorer;
296307

297-
MatchAndScore(ESLogger logger, PercolateContext context, HighlightPhase highlightPhase) {
298-
super(logger, context);
308+
MatchAndScore(ESLogger logger, PercolateContext context, HighlightPhase highlightPhase, boolean isNestedDoc) {
309+
super(logger, context, isNestedDoc);
299310
this.limit = context.limit;
300311
this.size = context.size();
301312
this.context = context;
@@ -316,7 +327,11 @@ public void collect(int doc) throws IOException {
316327
context.parsedQuery(new ParsedQuery(query, ImmutableMap.<String, Filter>of()));
317328
context.hitContext().cache().clear();
318329
}
319-
searcher.search(query, collector);
330+
if (isNestedDoc) {
331+
searcher.search(query, NonNestedDocsFilter.INSTANCE, collector);
332+
} else {
333+
searcher.search(query, collector);
334+
}
320335
if (collector.exists()) {
321336
if (!limit || counter < size) {
322337
matches.add(values.copyShared());
@@ -360,8 +375,8 @@ final static class Count extends QueryCollector {
360375

361376
private long counter = 0;
362377

363-
Count(ESLogger logger, PercolateContext context) {
364-
super(logger, context);
378+
Count(ESLogger logger, PercolateContext context, boolean isNestedDoc) {
379+
super(logger, context, isNestedDoc);
365380
}
366381

367382
@Override
@@ -374,7 +389,11 @@ public void collect(int doc) throws IOException {
374389
// run the query
375390
try {
376391
collector.reset();
377-
searcher.search(query, collector);
392+
if (isNestedDoc) {
393+
searcher.search(query, NonNestedDocsFilter.INSTANCE, collector);
394+
} else {
395+
searcher.search(query, collector);
396+
}
378397
if (collector.exists()) {
379398
counter++;
380399
postMatch(doc);

0 commit comments

Comments
 (0)