From 09fbb4d06d5576d8582715d622368e47b530ae46 Mon Sep 17 00:00:00 2001 From: Jim Ferenczi Date: Thu, 17 Nov 2016 18:45:34 +0100 Subject: [PATCH] Fix match_phrase_prefix on boosted fields (#21623) This change fixes the match_phrase_prefix on fields that define a boost in their mapping. Fixes #21613 --- .../index/search/MatchQuery.java | 32 ++++++++++------- .../index/query/MatchQueryBuilderTests.java | 36 +++++++++++++++++++ 2 files changed, 56 insertions(+), 12 deletions(-) diff --git a/core/src/main/java/org/elasticsearch/index/search/MatchQuery.java b/core/src/main/java/org/elasticsearch/index/search/MatchQuery.java index cf8be75306f..46eb6b7d399 100644 --- a/core/src/main/java/org/elasticsearch/index/search/MatchQuery.java +++ b/core/src/main/java/org/elasticsearch/index/search/MatchQuery.java @@ -25,6 +25,7 @@ import org.apache.lucene.queries.ExtendedCommonTermsQuery; import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.BooleanClause.Occur; import org.apache.lucene.search.BooleanQuery; +import org.apache.lucene.search.BoostQuery; import org.apache.lucene.search.FuzzyQuery; import org.apache.lucene.search.MultiPhraseQuery; import org.apache.lucene.search.MultiTermQuery; @@ -303,31 +304,38 @@ public class MatchQuery { public Query createPhrasePrefixQuery(String field, String queryText, int phraseSlop, int maxExpansions) { final Query query = createFieldQuery(getAnalyzer(), Occur.MUST, field, queryText, true, phraseSlop); + float boost = 1; + Query innerQuery = query; + while (innerQuery instanceof BoostQuery) { + BoostQuery bq = (BoostQuery) innerQuery; + boost *= bq.getBoost(); + innerQuery = bq.getQuery(); + } final MultiPhrasePrefixQuery prefixQuery = new MultiPhrasePrefixQuery(); prefixQuery.setMaxExpansions(maxExpansions); prefixQuery.setSlop(phraseSlop); - if (query instanceof PhraseQuery) { - PhraseQuery pq = (PhraseQuery)query; + if (innerQuery instanceof PhraseQuery) { + PhraseQuery pq = (PhraseQuery) innerQuery; Term[] terms = pq.getTerms(); int[] positions = pq.getPositions(); for (int i = 0; i < terms.length; i++) { prefixQuery.add(new Term[] {terms[i]}, positions[i]); } - return prefixQuery; - } else if (query instanceof MultiPhraseQuery) { - MultiPhraseQuery pq = (MultiPhraseQuery)query; + return boost == 1 ? prefixQuery : new BoostQuery(prefixQuery, boost); + } else if (innerQuery instanceof MultiPhraseQuery) { + MultiPhraseQuery pq = (MultiPhraseQuery) innerQuery; Term[][] terms = pq.getTermArrays(); int[] positions = pq.getPositions(); for (int i = 0; i < terms.length; i++) { prefixQuery.add(terms[i], positions[i]); } - return prefixQuery; - } else if (query instanceof TermQuery) { - prefixQuery.add(((TermQuery) query).getTerm()); - return prefixQuery; - } else if (query instanceof AllTermQuery) { - prefixQuery.add(((AllTermQuery) query).getTerm()); - return prefixQuery; + return boost == 1 ? prefixQuery : new BoostQuery(prefixQuery, boost); + } else if (innerQuery instanceof TermQuery) { + prefixQuery.add(((TermQuery) innerQuery).getTerm()); + return boost == 1 ? prefixQuery : new BoostQuery(prefixQuery, boost); + } else if (innerQuery instanceof AllTermQuery) { + prefixQuery.add(((AllTermQuery) innerQuery).getTerm()); + return boost == 1 ? prefixQuery : new BoostQuery(prefixQuery, boost); } return query; } diff --git a/core/src/test/java/org/elasticsearch/index/query/MatchQueryBuilderTests.java b/core/src/test/java/org/elasticsearch/index/query/MatchQueryBuilderTests.java index a4e202e2304..00d41aa754e 100644 --- a/core/src/test/java/org/elasticsearch/index/query/MatchQueryBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/index/query/MatchQueryBuilderTests.java @@ -22,6 +22,7 @@ package org.elasticsearch.index.query; import org.apache.lucene.queries.ExtendedCommonTermsQuery; import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.BooleanQuery; +import org.apache.lucene.search.BoostQuery; import org.apache.lucene.search.FuzzyQuery; import org.apache.lucene.search.MatchAllDocsQuery; import org.apache.lucene.search.MatchNoDocsQuery; @@ -29,11 +30,15 @@ import org.apache.lucene.search.PhraseQuery; import org.apache.lucene.search.PointRangeQuery; import org.apache.lucene.search.Query; import org.apache.lucene.search.TermQuery; +import org.elasticsearch.Version; +import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; import org.elasticsearch.common.ParseFieldMatcher; import org.elasticsearch.common.ParsingException; +import org.elasticsearch.common.compress.CompressedXContent; import org.elasticsearch.common.lucene.search.MultiPhrasePrefixQuery; import org.elasticsearch.common.lucene.search.Queries; import org.elasticsearch.index.mapper.MappedFieldType; +import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.index.search.MatchQuery; import org.elasticsearch.index.search.MatchQuery.Type; import org.elasticsearch.index.search.MatchQuery.ZeroTermsQuery; @@ -458,4 +463,35 @@ public class MatchQueryBuilderTests extends AbstractQueryTestCase parseQuery(json2)); } + + @Override + protected void initializeAdditionalMappings(MapperService mapperService) throws IOException { + mapperService.merge("t_boost", new CompressedXContent(PutMappingRequest.buildFromSimplifiedDef("t_boost", + "string_boost", "type=text,boost=4").string()), MapperService.MergeReason.MAPPING_UPDATE, false); + } + + public void testMatchPhrasePrefixWithBoost() throws Exception { + assumeTrue("test runs only when at least a type is registered", getCurrentTypes().length > 0); + QueryShardContext context = createShardContext(); + assumeTrue("test runs only when the index version is on or after V_5_0_0_alpha1", + context.indexVersionCreated().onOrAfter(Version.V_5_0_0_alpha1)); + + { + // field boost is applied on a single term query + MatchPhrasePrefixQueryBuilder builder = new MatchPhrasePrefixQueryBuilder("string_boost", "foo"); + Query query = builder.toQuery(context); + assertThat(query, instanceOf(BoostQuery.class)); + assertThat(((BoostQuery) query).getBoost(), equalTo(4f)); + Query innerQuery = ((BoostQuery) query).getQuery(); + assertThat(innerQuery, instanceOf(MultiPhrasePrefixQuery.class)); + } + + { + // field boost is ignored on phrase query + MatchPhrasePrefixQueryBuilder builder = new MatchPhrasePrefixQueryBuilder("string_boost", "foo bar"); + Query query = builder.toQuery(context); + assertThat(query, instanceOf(MultiPhrasePrefixQuery.class)); + } + + } }