mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-02-17 10:25:15 +00:00
Handle MatchNoDocsQuery in span query wrappers (#34106)
* Handle MatchNoDocsQuery in span query wrappers This change adds a new SpanMatchNoDocsQuery query that replaces MatchNoDocsQuery in the span query wrappers. The `wildcard` query now returns MatchNoDocsQuery if the target field is not in the mapping (#34093) so we need the equivalent span query in order to be able to pass it to other span wrappers. Closes #34105
This commit is contained in:
parent
cb4cdf17f0
commit
269ae0bc15
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.lucene.queries;
|
||||
|
||||
import org.apache.lucene.index.LeafReaderContext;
|
||||
import org.apache.lucene.index.Term;
|
||||
import org.apache.lucene.index.TermStates;
|
||||
import org.apache.lucene.search.IndexSearcher;
|
||||
import org.apache.lucene.search.ScoreMode;
|
||||
import org.apache.lucene.search.spans.SpanQuery;
|
||||
import org.apache.lucene.search.spans.SpanWeight;
|
||||
import org.apache.lucene.search.spans.Spans;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A {@link SpanQuery} that matches no documents.
|
||||
*/
|
||||
public class SpanMatchNoDocsQuery extends SpanQuery {
|
||||
private final String field;
|
||||
private final String reason;
|
||||
|
||||
public SpanMatchNoDocsQuery(String field, String reason) {
|
||||
this.field = field;
|
||||
this.reason = reason;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getField() {
|
||||
return field;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(String field) {
|
||||
return "SpanMatchNoDocsQuery(\"" + reason + "\")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return sameClassAs(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return classHash();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpanWeight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException {
|
||||
return new SpanWeight(this, searcher, Collections.emptyMap(), boost) {
|
||||
@Override
|
||||
public void extractTermStates(Map<Term, TermStates> contexts) {}
|
||||
|
||||
@Override
|
||||
public Spans getSpans(LeafReaderContext ctx, Postings requiredPostings) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void extractTerms(Set<Term> terms) {}
|
||||
|
||||
@Override
|
||||
public boolean isCacheable(LeafReaderContext ctx) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -181,6 +181,7 @@ public class FuzzyQueryBuilder extends AbstractQueryBuilder<FuzzyQueryBuilder> i
|
||||
out.writeOptionalString(this.rewrite);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String fieldName() {
|
||||
return this.fieldName;
|
||||
}
|
||||
|
@ -19,5 +19,8 @@
|
||||
package org.elasticsearch.index.query;
|
||||
|
||||
public interface MultiTermQueryBuilder extends QueryBuilder {
|
||||
|
||||
/**
|
||||
* Get the field name for this query.
|
||||
*/
|
||||
String fieldName();
|
||||
}
|
||||
|
@ -87,6 +87,7 @@ public class PrefixQueryBuilder extends AbstractQueryBuilder<PrefixQueryBuilder>
|
||||
out.writeOptionalString(rewrite);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String fieldName() {
|
||||
return this.fieldName;
|
||||
}
|
||||
|
@ -146,6 +146,7 @@ public class RangeQueryBuilder extends AbstractQueryBuilder<RangeQueryBuilder> i
|
||||
/**
|
||||
* Get the field name for this query.
|
||||
*/
|
||||
@Override
|
||||
public String fieldName() {
|
||||
return this.fieldName;
|
||||
}
|
||||
|
@ -104,6 +104,7 @@ public class RegexpQueryBuilder extends AbstractQueryBuilder<RegexpQueryBuilder>
|
||||
}
|
||||
|
||||
/** Returns the field name used in this query. */
|
||||
@Override
|
||||
public String fieldName() {
|
||||
return this.fieldName;
|
||||
}
|
||||
|
@ -21,9 +21,11 @@ package org.elasticsearch.index.query;
|
||||
import org.apache.lucene.index.Term;
|
||||
import org.apache.lucene.index.IndexReader;
|
||||
import org.apache.lucene.index.TermStates;
|
||||
import org.apache.lucene.queries.SpanMatchNoDocsQuery;
|
||||
import org.apache.lucene.search.BooleanQuery;
|
||||
import org.apache.lucene.search.BoostQuery;
|
||||
import org.apache.lucene.search.ConstantScoreQuery;
|
||||
import org.apache.lucene.search.MatchNoDocsQuery;
|
||||
import org.apache.lucene.search.MultiTermQuery;
|
||||
import org.apache.lucene.search.PrefixQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
@ -190,9 +192,14 @@ public class SpanMultiTermQueryBuilder extends AbstractQueryBuilder<SpanMultiTer
|
||||
break;
|
||||
}
|
||||
}
|
||||
final SpanQuery spanQuery;
|
||||
// no MultiTermQuery extends SpanQuery, so SpanBoostQuery is not supported here
|
||||
assert subQuery instanceof SpanBoostQuery == false;
|
||||
|
||||
if (subQuery instanceof MatchNoDocsQuery) {
|
||||
return new SpanMatchNoDocsQuery(multiTermQueryBuilder.fieldName(), subQuery.toString());
|
||||
}
|
||||
|
||||
final SpanQuery spanQuery;
|
||||
if (subQuery instanceof TermQuery) {
|
||||
/**
|
||||
* Text fields that index prefixes can rewrite prefix queries
|
||||
|
@ -96,6 +96,7 @@ public class WildcardQueryBuilder extends AbstractQueryBuilder<WildcardQueryBuil
|
||||
out.writeOptionalString(rewrite);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String fieldName() {
|
||||
return fieldName;
|
||||
}
|
||||
|
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.apache.lucene.queries;
|
||||
|
||||
import org.apache.lucene.analysis.Analyzer;
|
||||
import org.apache.lucene.analysis.MockAnalyzer;
|
||||
import org.apache.lucene.document.Document;
|
||||
import org.apache.lucene.document.Field;
|
||||
import org.apache.lucene.index.DirectoryReader;
|
||||
import org.apache.lucene.index.IndexReader;
|
||||
import org.apache.lucene.index.IndexWriter;
|
||||
import org.apache.lucene.index.Term;
|
||||
import org.apache.lucene.search.IndexSearcher;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.search.QueryUtils;
|
||||
import org.apache.lucene.search.ScoreDoc;
|
||||
import org.apache.lucene.search.spans.SpanNearQuery;
|
||||
import org.apache.lucene.search.spans.SpanOrQuery;
|
||||
import org.apache.lucene.search.spans.SpanQuery;
|
||||
import org.apache.lucene.search.spans.SpanTermQuery;
|
||||
import org.apache.lucene.store.Directory;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class SpanMatchNoDocsQueryTests extends ESTestCase {
|
||||
public void testSimple() throws Exception {
|
||||
SpanMatchNoDocsQuery query = new SpanMatchNoDocsQuery("field", "a good reason");
|
||||
assertEquals(query.toString(), "SpanMatchNoDocsQuery(\"a good reason\")");
|
||||
Query rewrite = query.rewrite(null);
|
||||
assertTrue(rewrite instanceof SpanMatchNoDocsQuery);
|
||||
assertEquals(rewrite.toString(), "SpanMatchNoDocsQuery(\"a good reason\")");
|
||||
}
|
||||
|
||||
public void testQuery() throws Exception {
|
||||
Directory dir = newDirectory();
|
||||
Analyzer analyzer = new MockAnalyzer(random());
|
||||
IndexWriter iw = new IndexWriter(dir,
|
||||
newIndexWriterConfig(analyzer).setMaxBufferedDocs(2).setMergePolicy(newLogMergePolicy()));
|
||||
addDoc("one", iw);
|
||||
addDoc("two", iw);
|
||||
addDoc("three", iw);
|
||||
IndexReader ir = DirectoryReader.open(iw);
|
||||
IndexSearcher searcher = new IndexSearcher(ir);
|
||||
|
||||
Query query = new SpanMatchNoDocsQuery("unkwown", "field not found");
|
||||
assertEquals(searcher.count(query), 0);
|
||||
|
||||
ScoreDoc[] hits;
|
||||
hits = searcher.search(query, 1000).scoreDocs;
|
||||
assertEquals(0, hits.length);
|
||||
assertEquals(query.toString(), "SpanMatchNoDocsQuery(\"field not found\")");
|
||||
|
||||
SpanOrQuery orQuery = new SpanOrQuery(
|
||||
new SpanMatchNoDocsQuery("unknown", "field not found"),
|
||||
new SpanTermQuery(new Term("unknown", "one"))
|
||||
);
|
||||
assertEquals(searcher.count(orQuery), 0);
|
||||
hits = searcher.search(orQuery, 1000).scoreDocs;
|
||||
assertEquals(0, hits.length);
|
||||
|
||||
orQuery = new SpanOrQuery(
|
||||
new SpanMatchNoDocsQuery("key", "a good reason"),
|
||||
new SpanTermQuery(new Term("key", "one"))
|
||||
);
|
||||
assertEquals(searcher.count(orQuery), 1);
|
||||
hits = searcher.search(orQuery, 1000).scoreDocs;
|
||||
assertEquals(1, hits.length);
|
||||
Query rewrite = orQuery.rewrite(ir);
|
||||
assertEquals(rewrite, orQuery);
|
||||
|
||||
SpanNearQuery nearQuery = new SpanNearQuery(
|
||||
new SpanQuery[] {new SpanMatchNoDocsQuery("same", ""), new SpanMatchNoDocsQuery("same", "")},
|
||||
0, true);
|
||||
assertEquals(searcher.count(nearQuery), 0);
|
||||
hits = searcher.search(nearQuery, 1000).scoreDocs;
|
||||
assertEquals(0, hits.length);
|
||||
rewrite = nearQuery.rewrite(ir);
|
||||
assertEquals(rewrite, nearQuery);
|
||||
|
||||
iw.close();
|
||||
ir.close();
|
||||
dir.close();
|
||||
}
|
||||
|
||||
public void testEquals() {
|
||||
Query q1 = new SpanMatchNoDocsQuery("key1", "one");
|
||||
Query q2 = new SpanMatchNoDocsQuery("key2", "two");
|
||||
assertTrue(q1.equals(q2));
|
||||
QueryUtils.check(q1);
|
||||
}
|
||||
|
||||
private void addDoc(String text, IndexWriter iw) throws IOException {
|
||||
Document doc = new Document();
|
||||
Field f = newTextField("key", text, Field.Store.YES);
|
||||
doc.add(f);
|
||||
iw.addDocument(doc);
|
||||
}
|
||||
|
||||
}
|
@ -25,6 +25,7 @@ import org.apache.lucene.document.TextField;
|
||||
import org.apache.lucene.index.IndexReader;
|
||||
import org.apache.lucene.index.RandomIndexWriter;
|
||||
import org.apache.lucene.index.Term;
|
||||
import org.apache.lucene.queries.SpanMatchNoDocsQuery;
|
||||
import org.apache.lucene.search.BooleanQuery;
|
||||
import org.apache.lucene.search.BoostQuery;
|
||||
import org.apache.lucene.search.MultiTermQuery;
|
||||
@ -81,6 +82,9 @@ public class SpanMultiTermQueryBuilderTests extends AbstractQueryTestCase<SpanMu
|
||||
|
||||
@Override
|
||||
protected void doAssertLuceneQuery(SpanMultiTermQueryBuilder queryBuilder, Query query, SearchContext context) throws IOException {
|
||||
if (query instanceof SpanMatchNoDocsQuery) {
|
||||
return;
|
||||
}
|
||||
if (queryBuilder.innerQuery().boost() != AbstractQueryBuilder.DEFAULT_BOOST) {
|
||||
assertThat(query, instanceOf(SpanBoostQuery.class));
|
||||
SpanBoostQuery boostQuery = (SpanBoostQuery) query;
|
||||
@ -97,7 +101,7 @@ public class SpanMultiTermQueryBuilderTests extends AbstractQueryTestCase<SpanMu
|
||||
}
|
||||
assertThat(multiTermQuery, either(instanceOf(MultiTermQuery.class)).or(instanceOf(TermQuery.class)));
|
||||
assertThat(spanMultiTermQueryWrapper.getWrappedQuery(),
|
||||
equalTo(new SpanMultiTermQueryWrapper<>((MultiTermQuery)multiTermQuery).getWrappedQuery()));
|
||||
equalTo(new SpanMultiTermQueryWrapper<>((MultiTermQuery) multiTermQuery).getWrappedQuery()));
|
||||
}
|
||||
|
||||
public void testIllegalArgument() {
|
||||
@ -154,6 +158,11 @@ public class SpanMultiTermQueryBuilderTests extends AbstractQueryTestCase<SpanMu
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String fieldName() {
|
||||
return "foo";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
package org.elasticsearch.index.query;
|
||||
|
||||
import org.apache.lucene.queries.SpanMatchNoDocsQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.search.spans.SpanBoostQuery;
|
||||
import org.apache.lucene.search.spans.SpanNearQuery;
|
||||
@ -53,6 +54,7 @@ public class SpanNearQueryBuilderTests extends AbstractQueryTestCase<SpanNearQue
|
||||
assertThat(query, either(instanceOf(SpanNearQuery.class))
|
||||
.or(instanceOf(SpanTermQuery.class))
|
||||
.or(instanceOf(SpanBoostQuery.class))
|
||||
.or(instanceOf(SpanMatchNoDocsQuery.class))
|
||||
.or(instanceOf(MatchAllQueryBuilder.class)));
|
||||
if (query instanceof SpanNearQuery) {
|
||||
SpanNearQuery spanNearQuery = (SpanNearQuery) query;
|
||||
|
@ -406,7 +406,6 @@ public abstract class AbstractQueryTestCase<QB extends AbstractQueryBuilder<QB>>
|
||||
* Test creates the {@link Query} from the {@link QueryBuilder} under test and delegates the
|
||||
* assertions being made on the result to the implementing subclass.
|
||||
*/
|
||||
@AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/34105")
|
||||
public void testToQuery() throws IOException {
|
||||
for (int runs = 0; runs < NUMBER_OF_TESTQUERIES; runs++) {
|
||||
QueryShardContext context = createShardContext();
|
||||
|
Loading…
x
Reference in New Issue
Block a user