[ES|QL] Optimize vector similarity when one param is constant#135602
[ES|QL] Optimize vector similarity when one param is constant#135602pmpailis merged 27 commits intoelastic:mainfrom
Conversation
…ctor_similarity_when_constant
…github.com:pmpailis/elasticsearch into pb_134210_optimize_vector_similarity_when_constant
carlosdelest
left a comment
There was a problem hiding this comment.
This LGTM - a question about creating multiple subclasses
| public final EvalOperator.ExpressionEvaluator.Factory toEvaluator(EvaluatorMapper.ToEvaluator toEvaluator) { | ||
| VectorValueProvider.Builder leftVectorProviderBuilder = new VectorValueProvider.Builder(); | ||
| VectorValueProvider.Builder rightVectorProviderBuilder = new VectorValueProvider.Builder(); | ||
| if (left() instanceof Literal && left().dataType() == DENSE_VECTOR) { |
There was a problem hiding this comment.
I think you can count on the arguments being type dense_vector, it is already checked as part of checkDenseVectorParam() and would have been caught at the Analyzer level
| private FloatBlock block; | ||
| private float[] scratch; | ||
|
|
||
| VectorValueProvider(ArrayList<Float> constantVector, EvalOperator.ExpressionEvaluator expressionEvaluator) { |
There was a problem hiding this comment.
Good idea to use a class to wrap the different ways of retrieving vectors!
Would it make sense to create two separate subclasses, so we don't need to keep checking for what has been provided?
There was a problem hiding this comment.
That's a nice suggestion and will make things easier to follow, thanks! Will refactor to have 2 subclasses.
|
Pinging @elastic/es-search-relevance (Team:Search Relevance) |
| assumeTrue("Similarity function is not enabled", capability().isEnabled()); | ||
| } | ||
|
|
||
| public abstract String getBaseEvaluatorName(); |
There was a problem hiding this comment.
@carlosdelest trying to find a better way to access this as we already pass it in the similarityParameters , but it was getting a bit too complicated for a small-scoped change, as the PR only affects the similarity functions. Happy to discuss alternatives :)
|
run elasticsearch-ci/part-3 |
|
|
||
| /** | ||
| * Fields with this type are dense vectors, represented as an array of double values. | ||
| * Fields with this type are dense vectors, represented as an array of float values. |
| } | ||
|
|
||
| @Override | ||
| public String toString() { |
There was a problem hiding this comment.
What do you think about creating a different factory for each type of VectorValueProvider, both of them implementing the same interface?
That would help with not having to check which of the two fields need to be used. Each of the classes would have its build() and toString() methods.
I think it makes sense as the factories create two different objects - makes sense to make them different.
Maybe it¡s a bit convoluted for what we're doing but probably cleaner. WDYT?
There was a problem hiding this comment.
++ makes sense. Didn't want to have a ton of new factories/interfaces, but it will be cleaner. Will refactor as suggested.
…github.com:pmpailis/elasticsearch into pb_134210_optimize_vector_similarity_when_constant
carlosdelest
left a comment
There was a problem hiding this comment.
Great work! Your first PR achieved such a speedup 🚀
| public final EvalOperator.ExpressionEvaluator.Factory toEvaluator(EvaluatorMapper.ToEvaluator toEvaluator) { | ||
| VectorValueProviderFactory leftVectorProviderFactory; | ||
| VectorValueProviderFactory rightVectorProviderFactory; | ||
| if (left() instanceof Literal) { |
There was a problem hiding this comment.
Nit - we could extract this to a private method
This PR aims to optimize the way we handle constant vectors in ES|QL vector similarity functions. The main idea is to reuse a single object and avoid duplicating and creating huge
FloatBlockinstances and identical float arrays.Benchmark results show a nice improvement for the script-score functions using the
so_vectorrally track:Closes #134210