-
Notifications
You must be signed in to change notification settings - Fork 25k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix index prefixes to work with span_multi #31066
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -40,6 +40,7 @@ | |
import org.apache.lucene.search.PhraseQuery; | ||
import org.apache.lucene.search.Query; | ||
import org.apache.lucene.search.TermQuery; | ||
import org.elasticsearch.Version; | ||
import org.elasticsearch.common.collect.Iterators; | ||
import org.elasticsearch.common.logging.ESLoggerFactory; | ||
import org.elasticsearch.common.settings.Settings; | ||
|
@@ -175,7 +176,11 @@ public TextFieldMapper build(BuilderContext context) { | |
if (fieldType().isSearchable() == false) { | ||
throw new IllegalArgumentException("Cannot set index_prefixes on unindexed field [" + name() + "]"); | ||
} | ||
if (fieldType.indexOptions() == IndexOptions.DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS) { | ||
// Copy the index options of the main field to allow phrase queries on | ||
// the prefix field. | ||
if (context.indexCreatedVersion().onOrAfter(Version.V_7_0_0_alpha1)) { | ||
prefixFieldType.setIndexOptions(fieldType.indexOptions()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should we map |
||
} else if (fieldType.indexOptions() == IndexOptions.DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS) { | ||
prefixFieldType.setIndexOptions(IndexOptions.DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS); | ||
} | ||
if (fieldType.storeTermVectorOffsets()) { | ||
|
@@ -339,7 +344,6 @@ static final class PrefixFieldType extends StringFieldType { | |
PrefixFieldType(String name, int minChars, int maxChars) { | ||
setTokenized(true); | ||
setOmitNorms(true); | ||
setIndexOptions(IndexOptions.DOCS); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we still need this? What happens with a 6.3 index that doesn't store offsets? |
||
setName(name); | ||
this.minChars = minChars; | ||
this.maxChars = maxChars; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,18 +18,28 @@ | |
*/ | ||
package org.elasticsearch.index.query; | ||
|
||
import org.apache.lucene.index.Term; | ||
import org.apache.lucene.search.BoostQuery; | ||
import org.apache.lucene.search.ConstantScoreQuery; | ||
import org.apache.lucene.search.MultiTermQuery; | ||
import org.apache.lucene.search.PrefixQuery; | ||
import org.apache.lucene.search.Query; | ||
import org.apache.lucene.search.TermQuery; | ||
import org.apache.lucene.search.spans.FieldMaskingSpanQuery; | ||
import org.apache.lucene.search.spans.SpanBoostQuery; | ||
import org.apache.lucene.search.spans.SpanMultiTermQueryWrapper; | ||
import org.apache.lucene.search.spans.SpanQuery; | ||
import org.apache.lucene.search.spans.SpanTermQuery; | ||
import org.elasticsearch.Version; | ||
import org.elasticsearch.common.ParseField; | ||
import org.elasticsearch.common.ParsingException; | ||
import org.elasticsearch.common.io.stream.StreamInput; | ||
import org.elasticsearch.common.io.stream.StreamOutput; | ||
import org.elasticsearch.common.xcontent.LoggingDeprecationHandler; | ||
import org.elasticsearch.common.xcontent.XContentBuilder; | ||
import org.elasticsearch.common.xcontent.XContentParser; | ||
import org.elasticsearch.index.mapper.TextFieldMapper; | ||
import org.elasticsearch.index.query.support.QueryParsers; | ||
|
||
import java.io.IOException; | ||
import java.util.Objects; | ||
|
@@ -124,22 +134,61 @@ public static SpanMultiTermQueryBuilder fromXContent(XContentParser parser) thro | |
protected Query doToQuery(QueryShardContext context) throws IOException { | ||
Query subQuery = multiTermQueryBuilder.toQuery(context); | ||
float boost = AbstractQueryBuilder.DEFAULT_BOOST; | ||
if (subQuery instanceof BoostQuery) { | ||
if (subQuery instanceof ConstantScoreQuery) { | ||
subQuery = ((ConstantScoreQuery) subQuery).getQuery(); | ||
} else if (subQuery instanceof BoostQuery) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should we unwrap recursively to be more resilient to changes to the way queries are built? |
||
BoostQuery boostQuery = (BoostQuery) subQuery; | ||
subQuery = boostQuery.getQuery(); | ||
boost = boostQuery.getBoost(); | ||
} | ||
//no MultiTermQuery extends SpanQuery, so SpanBoostQuery is not supported here | ||
final SpanQuery spanQuery; | ||
// no MultiTermQuery extends SpanQuery, so SpanBoostQuery is not supported here | ||
assert subQuery instanceof SpanBoostQuery == false; | ||
if (subQuery instanceof MultiTermQuery == false) { | ||
throw new UnsupportedOperationException("unsupported inner query, should be " + MultiTermQuery.class.getName() +" but was " | ||
+ subQuery.getClass().getName()); | ||
if (subQuery instanceof TermQuery) { | ||
/** | ||
* Text fields that index prefixes can rewrite prefix queries | ||
* into term queries. See {@link TextFieldMapper.TextFieldType#prefixQuery}. | ||
*/ | ||
if (multiTermQueryBuilder.getClass() != PrefixQueryBuilder.class) { | ||
throw new UnsupportedOperationException("unsupported inner query, should be " | ||
+ MultiTermQuery.class.getName() + " but was " + subQuery.getClass().getName()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. let's include the class of multiTermQueryBuilder to the error message as well? |
||
} | ||
if (context.getIndexSettings().getIndexVersionCreated().before(Version.V_7_0_0_alpha1)) { | ||
/** | ||
* Indices created in this version do not index positions on the prefix field | ||
* so we cannot use it to match positional queries. Instead, we explicitly create the prefix | ||
* query on the main field to avoid the rewrite. | ||
*/ | ||
PrefixQueryBuilder prefixBuilder = (PrefixQueryBuilder) multiTermQueryBuilder; | ||
PrefixQuery prefixQuery = new PrefixQuery(new Term(prefixBuilder.fieldName(), prefixBuilder.value())); | ||
if (prefixBuilder.rewrite() != null) { | ||
MultiTermQuery.RewriteMethod rewriteMethod = | ||
QueryParsers.parseRewriteMethod(prefixBuilder.rewrite(), null, LoggingDeprecationHandler.INSTANCE); | ||
prefixQuery.setRewriteMethod(rewriteMethod); | ||
} | ||
spanQuery = new SpanMultiTermQueryWrapper<>(prefixQuery); | ||
} else { | ||
String origFieldName = ((PrefixQueryBuilder) multiTermQueryBuilder).fieldName(); | ||
SpanTermQuery spanTermQuery = new SpanTermQuery(((TermQuery) subQuery).getTerm()); | ||
/** | ||
* Prefixes are indexed in a different field so we mask the term query with the original field | ||
* name. This is required because span_near and span_or queries don't work across different field. | ||
* The masking is safe because the prefix field is indexed using the same content than the original field | ||
* and the prefix analyzer preserves positions. | ||
*/ | ||
spanQuery = new FieldMaskingSpanQuery(spanTermQuery, origFieldName); | ||
} | ||
} else { | ||
if (subQuery instanceof MultiTermQuery == false) { | ||
throw new UnsupportedOperationException("unsupported inner query, should be " | ||
+ MultiTermQuery.class.getName() + " but was " + subQuery.getClass().getName()); | ||
} | ||
spanQuery = new SpanMultiTermQueryWrapper<>((MultiTermQuery) subQuery); | ||
} | ||
SpanQuery wrapper = new SpanMultiTermQueryWrapper<>((MultiTermQuery) subQuery); | ||
if (boost != AbstractQueryBuilder.DEFAULT_BOOST) { | ||
wrapper = new SpanBoostQuery(wrapper, boost); | ||
return new SpanBoostQuery(spanQuery, boost); | ||
} | ||
return wrapper; | ||
return spanQuery; | ||
} | ||
|
||
@Override | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this can already be set to 6_4 before the backport, can't it?