@Override public Query rewrite(IndexReader reader) throws IOException { Query innerRewrite = query.rewrite(reader); if (innerRewrite != query) { // Right now ToParentBlockJoinQuery always rewrites to a ToParentBlockJoinQuery // so the else block will never be used. It is useful in the case that // ToParentBlockJoinQuery one day starts to rewrite to a different query, eg. // a MatchNoDocsQuery if it realizes that it cannot match any docs and rewrites // to a MatchNoDocsQuery. In that case it would be fine to lose information // about the nested path. if (innerRewrite instanceof ToParentBlockJoinQuery) { return new ESToParentBlockJoinQuery((ToParentBlockJoinQuery) innerRewrite, path); } else { return innerRewrite; } } return super.rewrite(reader); }
@Override protected void assertAvgScoreMode(Query parentFilter, IndexSearcher searcher) throws IOException { MultiValueMode sortMode = MultiValueMode.AVG; Query childFilter = Queries.not(parentFilter); XFieldComparatorSource nestedComparatorSource = createFieldComparator("field2", sortMode, -127, createNested(searcher, parentFilter, childFilter)); Query query = new ToParentBlockJoinQuery(new ConstantScoreQuery(childFilter), new QueryBitSetProducer(parentFilter), ScoreMode.None); Sort sort = new Sort(new SortField("field2", nestedComparatorSource)); TopDocs topDocs = searcher.search(query, 5, sort); assertThat(topDocs.totalHits, equalTo(7)); assertThat(topDocs.scoreDocs.length, equalTo(5)); assertThat(topDocs.scoreDocs[0].doc, equalTo(11)); assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[0]).fields[0]).intValue(), equalTo(2)); assertThat(topDocs.scoreDocs[1].doc, equalTo(7)); assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[1]).fields[0]).intValue(), equalTo(2)); assertThat(topDocs.scoreDocs[2].doc, equalTo(3)); assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[2]).fields[0]).intValue(), equalTo(3)); assertThat(topDocs.scoreDocs[3].doc, equalTo(15)); assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[3]).fields[0]).intValue(), equalTo(3)); assertThat(topDocs.scoreDocs[4].doc, equalTo(19)); assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[4]).fields[0]).intValue(), equalTo(3)); }
protected void assertAvgScoreMode(Query parentFilter, IndexSearcher searcher, IndexFieldData.XFieldComparatorSource innerFieldComparator) throws IOException { MultiValueMode sortMode = MultiValueMode.AVG; Query childFilter = Queries.not(parentFilter); XFieldComparatorSource nestedComparatorSource = createFieldComparator("field2", sortMode, -127, createNested(searcher, parentFilter, childFilter)); Query query = new ToParentBlockJoinQuery(new ConstantScoreQuery(childFilter), new QueryBitSetProducer(parentFilter), ScoreMode.None); Sort sort = new Sort(new SortField("field2", nestedComparatorSource)); TopDocs topDocs = searcher.search(query, 5, sort); assertThat(topDocs.totalHits, equalTo(7)); assertThat(topDocs.scoreDocs.length, equalTo(5)); assertThat(topDocs.scoreDocs[0].doc, equalTo(11)); assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[0]).fields[0]).intValue(), equalTo(2)); assertThat(topDocs.scoreDocs[1].doc, equalTo(7)); assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[1]).fields[0]).intValue(), equalTo(2)); assertThat(topDocs.scoreDocs[2].doc, equalTo(3)); assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[2]).fields[0]).intValue(), equalTo(3)); assertThat(topDocs.scoreDocs[3].doc, equalTo(15)); assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[3]).fields[0]).intValue(), equalTo(3)); assertThat(topDocs.scoreDocs[4].doc, equalTo(19)); assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[4]).fields[0]).intValue(), equalTo(3)); }
protected void assertAvgScoreMode(Query parentFilter, IndexSearcher searcher) throws IOException { MultiValueMode sortMode = MultiValueMode.AVG; Query childFilter = Queries.not(parentFilter); XFieldComparatorSource nestedComparatorSource = createFieldComparator("field2", sortMode, -127, createNested(searcher, parentFilter, childFilter)); Query query = new ToParentBlockJoinQuery(new ConstantScoreQuery(childFilter), new QueryBitSetProducer(parentFilter), ScoreMode.None); Sort sort = new Sort(new SortField("field2", nestedComparatorSource)); TopDocs topDocs = searcher.search(query, 5, sort); assertThat(topDocs.totalHits, equalTo(7)); assertThat(topDocs.scoreDocs.length, equalTo(5)); assertThat(topDocs.scoreDocs[0].doc, equalTo(11)); assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[0]).fields[0]).intValue(), equalTo(2)); assertThat(topDocs.scoreDocs[1].doc, equalTo(3)); assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[1]).fields[0]).intValue(), equalTo(3)); assertThat(topDocs.scoreDocs[2].doc, equalTo(7)); assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[2]).fields[0]).intValue(), equalTo(3)); assertThat(topDocs.scoreDocs[3].doc, equalTo(15)); assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[3]).fields[0]).intValue(), equalTo(3)); assertThat(topDocs.scoreDocs[4].doc, equalTo(19)); assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[4]).fields[0]).intValue(), equalTo(4)); }
private Optional<Query> limitingFilter(Query query, boolean isNegated) { if (query instanceof SpanQuery) { return limitingFilterForSpan((SpanQuery) query, isNegated); } else if (query instanceof Filter) { return Optional.of(query); } else if (query instanceof BooleanQuery) { return boolQuery((BooleanQuery) query, isNegated); } else if (query instanceof TermQuery) { return Optional.of(query); } else if (query instanceof PhraseQuery) { return phraseFilter((PhraseQuery) query, isNegated); } else if (query instanceof MultiTermQuery) { return Optional.of(query); } else if (query instanceof WildcardPhraseQuery) { return wildcardPhraseFilter((WildcardPhraseQuery) query, isNegated); } else if (query instanceof ToParentBlockJoinQuery) { //This can be really bad for performance, if the nested query contains expensive operations (phrases/spans) //On the other hand, it is only slow if the field actually has any data, and we currently do not have // any data in the only nested text field (enrichments.sentences) return Optional.of(query); } else { //This should never happen, but if it does, it might be really bad for performance //logger.warn("failed to limit query, this should never happen. Query : [{}]", query.toString()); return Optional.of(query); } }
public ESToParentBlockJoinQuery(Query childQuery, BitSetProducer parentsFilter, ScoreMode scoreMode, String path) { this(new ToParentBlockJoinQuery(childQuery, parentsFilter, scoreMode), path); }
private ESToParentBlockJoinQuery(ToParentBlockJoinQuery query, String path) { this.query = query; this.path = path; }
@Override public Query parse(QueryParseContext parseContext) throws IOException, QueryParsingException { XContentParser parser = parseContext.parser(); final ToBlockJoinQueryBuilder builder = new ToBlockJoinQueryBuilder(parseContext); float boost = 1.0f; ScoreMode scoreMode = ScoreMode.Avg; String queryName = null; String currentFieldName = null; XContentParser.Token token; while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { if (token == XContentParser.Token.FIELD_NAME) { currentFieldName = parser.currentName(); } else if (token == XContentParser.Token.START_OBJECT) { if ("query".equals(currentFieldName)) { builder.query(); } else if (parseContext.parseFieldMatcher().match(currentFieldName, FILTER_FIELD)) { builder.filter(); } else if ("inner_hits".equals(currentFieldName)) { builder.setInnerHits(innerHitsQueryParserHelper.parse(parseContext)); } else { throw new QueryParsingException(parseContext, "[nested] query does not support [" + currentFieldName + "]"); } } else if (token.isValue()) { if ("path".equals(currentFieldName)) { builder.setPath(parser.text()); } else if ("boost".equals(currentFieldName)) { boost = parser.floatValue(); } else if ("score_mode".equals(currentFieldName) || "scoreMode".equals(currentFieldName)) { String sScoreMode = parser.text(); if ("avg".equals(sScoreMode)) { scoreMode = ScoreMode.Avg; } else if ("min".equals(sScoreMode)) { scoreMode = ScoreMode.Min; } else if ("max".equals(sScoreMode)) { scoreMode = ScoreMode.Max; } else if ("total".equals(sScoreMode) || "sum".equals(sScoreMode)) { scoreMode = ScoreMode.Total; } else if ("none".equals(sScoreMode)) { scoreMode = ScoreMode.None; } else { throw new QueryParsingException(parseContext, "illegal score_mode for nested query [" + sScoreMode + "]"); } } else if ("_name".equals(currentFieldName)) { queryName = parser.text(); } else { throw new QueryParsingException(parseContext, "[nested] query does not support [" + currentFieldName + "]"); } } } builder.setScoreMode(scoreMode); ToParentBlockJoinQuery joinQuery = builder.build(); if (joinQuery != null) { joinQuery.setBoost(boost); if (queryName != null) { parseContext.addNamedQuery(queryName, joinQuery); } } return joinQuery; }
protected Query createQuery(Query parentList, Query query) { return new ToParentBlockJoinQuery(query, getFilter(parentList), ScoreMode.None); }
protected ToParentBlockJoinQuery join(final String childTerm) { return new ToParentBlockJoinQuery( new TermQuery(new Term(child, childTerm)), new TermRangeFilter(parent, null, null, false, false), ScoreMode.None); }
public static void main(String[] args) throws IOException { Directory dir = new RAMDirectory(); Analyzer analyzer = new StandardAnalyzer(); IndexWriterConfig iwc = new IndexWriterConfig(analyzer); iwc.setOpenMode(IndexWriterConfig.OpenMode.CREATE); IndexWriter writer = new IndexWriter(dir, iwc); // first block final Document sku1_1 = new Document(); sku1_1.add(new TextField("color", "red", Field.Store.YES)); sku1_1.add(new TextField("size", "xl", Field.Store.YES)); sku1_1.add(new TextField("type", "sku", Field.Store.YES)); final Document sku1_2 = new Document(); sku1_2.add(new TextField("color", "blue", Field.Store.YES)); sku1_2.add(new TextField("size", "m", Field.Store.YES)); sku1_2.add(new TextField("type", "sku", Field.Store.YES)); final Document product1 = new Document(); product1.add(new TextField("brand", "adidas", Field.Store.YES)); product1.add(new TextField("title", "dress", Field.Store.YES)); product1.add(new TextField("type", "product", Field.Store.YES)); writer.addDocuments(Arrays.asList(new Document[] {sku1_1, sku1_2, product1})); // second block final Document sku2_1 = new Document(); sku2_1.add(new TextField("color", "red", Field.Store.YES)); sku2_1.add(new TextField("size", "m", Field.Store.YES)); sku2_1.add(new TextField("type", "sku", Field.Store.YES)); final Document sk2_2 = new Document(); sk2_2.add(new TextField("color", "blue", Field.Store.YES)); sk2_2.add(new TextField("size", "xl", Field.Store.YES)); sk2_2.add(new TextField("type", "sku", Field.Store.YES)); final Document product2 = new Document(); product2.add(new TextField("brand", "puma", Field.Store.YES)); product2.add(new TextField("title", "dress", Field.Store.YES)); product2.add(new TextField("type", "product", Field.Store.YES)); writer.addDocuments(Arrays.asList(new Document[] {sku2_1, sk2_2, product2})); writer.close(); IndexReader reader = DirectoryReader.open(dir); IndexSearcher searcher = new IndexSearcher(reader); // i want to find out all products of the query red m dress BooleanQuery.Builder builder = new BooleanQuery.Builder(); BooleanQuery childQuery = builder.build(); ToParentBlockJoinQuery parentQuery = new ToParentBlockJoinQuery( childQuery, new QueryBitSetProducer(new TermQuery(new Term("type", "product"))), ScoreMode.Avg); System.out.println("query: " + parentQuery); TopDocs results = searcher.search(parentQuery, 100); ScoreDoc[] scoreDocs = results.scoreDocs; for (int i = 0; i < scoreDocs.length; ++i) { System.out.println(searcher.explain(parentQuery, scoreDocs[i].doc)); } }