Skip to content

Conversation

@afoucret
Copy link
Contributor

This PR introduces constant folding optimization for the TEXT_EMBEDDING function in ESQL.

Key components:

  • InferenceFunctionEvaluator: a new piece of infrastructure that uses an InferenceOperator to evaluate an inference function. Currently, only folding of constants is supported, but it could be extended to more use cases in the future.

  • Added a rules mechanism to the LogicalPlanPreOptimizer and introduced a rule that folds inference functions (FoldInferenceFunctions)

  • Adding CSV tests for the TEXT_EMBEDDING function, including usage with other vector functions such as KNN)

Part of #131022

@elasticsearchmachine elasticsearchmachine added needs:triage Requires assignment of a team area label v9.2.0 labels Sep 30, 2025
@afoucret afoucret added >non-issue Team:Search Relevance Meta label for the Search Relevance team in Elasticsearch :Search Relevance/ES|QL Search functionality in ES|QL and removed needs:triage Requires assignment of a team area label labels Sep 30, 2025
@elasticsearchmachine
Copy link
Collaborator

Pinging @elastic/es-search-relevance (Team:Search Relevance)

@afoucret afoucret requested review from a team, carlosdelest and ioanatia October 1, 2025 06:45
@afoucret afoucret force-pushed the esql_text_embedding_function_evaluator branch from dc7ac08 to aaec4e1 Compare October 1, 2025 08:39
@github-actions
Copy link
Contributor

github-actions bot commented Oct 1, 2025

ℹ️ Important: Docs version tagging

👋 Thanks for updating the docs! Just a friendly reminder that our docs are now cumulative. This means all 9.x versions are documented on the same page and published off of the main branch, instead of creating separate pages for each minor version.

We use applies_to tags to mark version-specific features and changes.

Expand for a quick overview

When to use applies_to tags:

✅ At the page level to indicate which products/deployments the content applies to (mandatory)
✅ When features change state (e.g. preview, ga) in a specific version
✅ When availability differs across deployments and environments

What NOT to do:

❌ Don't remove or replace information that applies to an older version
❌ Don't add new information that applies to a specific version without an applies_to tag
❌ Don't forget that applies_to tags can be used at the page, section, and inline level

🤔 Need help?

import static org.hamcrest.Matchers.equalTo;

@FunctionName("text_embedding")
public class TextEmbeddingTests extends AbstractFunctionTestCase {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ This tests were not added before because they were an issue while the dense vector type was under construction.

@@ -0,0 +1,6 @@
% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ Doc update are caused by the dense vector type being out of snapshot.

@afoucret afoucret added v9.3.0 and removed v9.2.0 labels Oct 2, 2025
;
// end::embedding-eval[]

input:keyword | embedding:dense_vector
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we get a test with multiple text_embedding calls with different query strings?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a CSV test with FORK that should be covering your ask:

FROM semantic_text METADATA _score
| FORK (EVAL query_embedding = TEXT_EMBEDDING("be excellent to each other", "test_dense_inference") | WHERE KNN(semantic_text_dense_field, query_embedding))
       (EVAL query_embedding = TEXT_EMBEDDING("live long and prosper", "test_dense_inference") | WHERE KNN(semantic_text_dense_field, query_embedding))
| KEEP semantic_text_field, query_embedding, _score, _fork
| EVAL _score = ROUND(_score, 4)
| SORT _score DESC
| LIMIT 10
;

semantic_text_field:text                                              | query_embedding:dense_vector | _fork:keyword | _score:double
be excellent to each other                                            | [45.0, 55.0, 54.0]           | fork1         | 1.0
live long and prosper                                                 | [50.0, 57.0, 56.0]           | fork2         | 1.0
be excellent to each other                                            | [50.0, 57.0, 56.0]           | fork2         | 0.0295
live long and prosper                                                 | [45.0, 55.0, 54.0]           | fork1         | 0.0295
all we have to decide is what to do with the time that is given to us | [45.0, 55.0, 54.0]           | fork1         | 0.0214
all we have to decide is what to do with the time that is given to us | [50.0, 57.0, 56.0]           | fork2         | 0.0109

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

plus it tests inference function in the context of fork

Copy link
Member

@carlosdelest carlosdelest left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 💯

* Example transformation:
* {@code TEXT_EMBEDDING("hello world", "model1")} → {@code [0.1, 0.2, 0.3, ...]}
*/
public class FoldInferenceFunctions implements LogicalPlanPreOptimizerRule {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess something like this would also be used for folding COMPLETION when it's used with a foldable prompt?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right. There will be something similar for inference plans.

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class InferenceFunctionEvaluatorTests extends ComputeTestCase {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should these be skipped for release tests?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I double-checked and it is not necessary.
The test is passing in release build since it does not use features that change in release build (function registry, writeable, ...)

@afoucret afoucret enabled auto-merge (squash) October 7, 2025 08:10
@afoucret afoucret merged commit f9c72c1 into elastic:main Oct 7, 2025
34 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

>non-issue :Search Relevance/ES|QL Search functionality in ES|QL Team:Search Relevance Meta label for the Search Relevance team in Elasticsearch v9.3.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants