-
Notifications
You must be signed in to change notification settings - Fork 24.9k
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
Two queries for keyword script field #59527
Changes from 2 commits
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 |
---|---|---|
@@ -0,0 +1,105 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License; | ||
* you may not use this file except in compliance with the Elastic License. | ||
*/ | ||
|
||
package org.elasticsearch.xpack.runtimefields.query; | ||
|
||
import org.apache.lucene.index.LeafReaderContext; | ||
import org.apache.lucene.search.ConstantScoreScorer; | ||
import org.apache.lucene.search.ConstantScoreWeight; | ||
import org.apache.lucene.search.DocIdSetIterator; | ||
import org.apache.lucene.search.IndexSearcher; | ||
import org.apache.lucene.search.Query; | ||
import org.apache.lucene.search.ScoreMode; | ||
import org.apache.lucene.search.Scorer; | ||
import org.apache.lucene.search.TwoPhaseIterator; | ||
import org.apache.lucene.search.Weight; | ||
import org.elasticsearch.xpack.runtimefields.StringScriptFieldScript; | ||
import org.elasticsearch.xpack.runtimefields.StringScriptFieldScript.LeafFactory; | ||
|
||
import java.io.IOException; | ||
import java.util.List; | ||
import java.util.Objects; | ||
|
||
/** | ||
* Abstract base class for building queries based on {@link StringScriptFieldScript}. | ||
*/ | ||
abstract class AbstractStringScriptFieldQuery extends Query { | ||
private final StringScriptFieldScript.LeafFactory leafFactory; | ||
private final String fieldName; | ||
|
||
AbstractStringScriptFieldQuery(LeafFactory leafFactory, String fieldName) { | ||
this.leafFactory = Objects.requireNonNull(leafFactory); | ||
this.fieldName = Objects.requireNonNull(fieldName); | ||
} | ||
|
||
/** | ||
* Does the value match this query? | ||
*/ | ||
public abstract boolean matches(List<String> values); | ||
|
||
/** | ||
* Builds the portion of {@link #toString()} that comes from the core of the query. | ||
* See {@link Query#toString(String)} for how queries handle {@link #fieldName}. | ||
*/ | ||
public abstract String bareToString(); | ||
|
||
@Override | ||
public final Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { | ||
return new ConstantScoreWeight(this, boost) { | ||
@Override | ||
public boolean isCacheable(LeafReaderContext ctx) { | ||
return false; // scripts aren't really cacheable at this point | ||
} | ||
|
||
@Override | ||
public Scorer scorer(LeafReaderContext ctx) throws IOException { | ||
StringScriptFieldScript script = leafFactory.newInstance(ctx); | ||
DocIdSetIterator approximation = DocIdSetIterator.all(ctx.reader().maxDoc()); | ||
TwoPhaseIterator twoPhase = new TwoPhaseIterator(approximation) { | ||
@Override | ||
public boolean matches() throws IOException { | ||
return AbstractStringScriptFieldQuery.this.matches(script.resultsForDoc(approximation().docID())); | ||
} | ||
|
||
@Override | ||
public float matchCost() { | ||
// TODO we don't have a good way of estimating the complexity of the script so we just go with 9000 | ||
return 9000f; | ||
} | ||
}; | ||
return new ConstantScoreScorer(this, score(), scoreMode, twoPhase); | ||
} | ||
}; | ||
} | ||
|
||
protected final String fieldName() { | ||
return fieldName; | ||
} | ||
|
||
@Override | ||
public final String toString(String field) { | ||
if (fieldName.contentEquals(field)) { | ||
return bareToString(); | ||
} | ||
return fieldName + ":" + bareToString(); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
// TODO should leafFactory be here? Something about the script probably should be! | ||
return Objects.hash(getClass(), fieldName); | ||
} | ||
|
||
@Override | ||
public boolean equals(Object obj) { | ||
if (obj == null || getClass() != obj.getClass()) { | ||
return false; | ||
} | ||
// TODO should leafFactory be here? Something about the script probably should be! | ||
AbstractStringScriptFieldQuery other = (AbstractStringScriptFieldQuery) obj; | ||
return fieldName.equals(other.fieldName); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License; | ||
* you may not use this file except in compliance with the Elastic License. | ||
*/ | ||
|
||
package org.elasticsearch.xpack.runtimefields.query; | ||
|
||
import org.elasticsearch.xpack.runtimefields.StringScriptFieldScript; | ||
|
||
import java.util.List; | ||
|
||
public class StringScriptFieldExistsQuery extends AbstractStringScriptFieldQuery { | ||
public StringScriptFieldExistsQuery(StringScriptFieldScript.LeafFactory leafFactory, String fieldName) { | ||
super(leafFactory, fieldName); | ||
} | ||
|
||
@Override | ||
public boolean matches(List<String> values) { | ||
return false == values.isEmpty(); | ||
} | ||
|
||
@Override | ||
public String bareToString() { | ||
return "*"; | ||
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 get it, but I find this cryptic. For instance looking at what DocValuesFieldExistsQuery does , that is clearer to me. 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 can keep the original |
||
} | ||
|
||
// Superclass's equals and hashCode are great for this class | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License; | ||
* you may not use this file except in compliance with the Elastic License. | ||
*/ | ||
|
||
package org.elasticsearch.xpack.runtimefields.query; | ||
|
||
import org.apache.lucene.index.Term; | ||
import org.apache.lucene.search.QueryVisitor; | ||
import org.elasticsearch.xpack.runtimefields.StringScriptFieldScript; | ||
|
||
import java.util.List; | ||
import java.util.Objects; | ||
import java.util.Set; | ||
|
||
public class StringScriptFieldTermsQuery extends AbstractStringScriptFieldQuery { | ||
private final Set<String> terms; | ||
|
||
public StringScriptFieldTermsQuery(StringScriptFieldScript.LeafFactory leafFactory, String fieldName, Set<String> terms) { | ||
super(leafFactory, fieldName); | ||
this.terms = terms; | ||
} | ||
|
||
@Override | ||
public boolean matches(List<String> values) { | ||
for (String value : values) { | ||
if (terms.contains(value)) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
@Override | ||
public void visit(QueryVisitor visitor) { | ||
if (visitor.acceptField(fieldName())) { | ||
for (String term : terms) { | ||
visitor.consumeTerms(this, new Term(fieldName(), term)); | ||
} | ||
} | ||
} | ||
|
||
@Override | ||
public String bareToString() { | ||
return terms.toString(); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return Objects.hash(super.hashCode(), terms); | ||
} | ||
|
||
@Override | ||
public boolean equals(Object obj) { | ||
if (false == super.equals(obj)) { | ||
return false; | ||
} | ||
StringScriptFieldTermsQuery other = (StringScriptFieldTermsQuery) obj; | ||
return other.terms.equals(other.terms); | ||
} | ||
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 have unit tests for equals/hashcode , toString and visit for all the queries that we introduce? 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. possibly also matches but that is already tested 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. Yeah. |
||
} |
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.
good point. what do we need to address this TODO? Would we need to pass in the Script itself?