This is an automated email from the ASF dual-hosted git repository.

wenjin272 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/flink-agents.git


The following commit(s) were added to refs/heads/main by this push:
     new ea5e5ea8 [plan][python] Remove split async vector-store query 
workaround (#1148)
ea5e5ea8 is described below

commit ea5e5ea89c1e76f8ea18ad766f9ee14d67a3ec44
Author: Wenjin Xie <[email protected]>
AuthorDate: Mon Sep 21 22:44:45 2026 +0800

    [plan][python] Remove split async vector-store query workaround (#1148)
    
    Generated-by: Codex CLI 0.153.4 (GPT-6)
    
    Co-authored-by: Codex <[email protected]>
---
 .../api/vectorstores/python/PythonVectorStore.java |  47 ---------
 .../test/VectorStoreCrossLanguageTest.java         |  24 +++--
 .../plan/actions/ContextRetrievalAction.java       | 114 ++++-----------------
 .../flink_agents/api/vector_stores/vector_store.py |  10 --
 .../vector_stores/chroma/chroma_vector_store.py    |  18 ----
 5 files changed, 38 insertions(+), 175 deletions(-)

diff --git 
a/api/src/main/java/org/apache/flink/agents/api/vectorstores/python/PythonVectorStore.java
 
b/api/src/main/java/org/apache/flink/agents/api/vectorstores/python/PythonVectorStore.java
index 4a393adc..7edf17c4 100644
--- 
a/api/src/main/java/org/apache/flink/agents/api/vectorstores/python/PythonVectorStore.java
+++ 
b/api/src/main/java/org/apache/flink/agents/api/vectorstores/python/PythonVectorStore.java
@@ -168,53 +168,6 @@ public class PythonVectorStore extends BaseVectorStore 
implements PythonResource
         }
     }
 
-    /** Embed query text via the configured model (no numpy, so it stays on 
the async pool). */
-    public float[] embedQuery(String text) {
-        return getEmbeddingModel().embed(text);
-    }
-
-    /**
-     * Convert the raw embedding to the Python store's native vector form. 
This runs the numpy
-     * conversion on the mailbox thread: numpy releases/re-acquires the GIL 
during the copy, and
-     * pemja keeps a single PyThreadState, so doing it on an async worker 
thread can stall the
-     * interpreter (observed as a hang in CI; benign with spare cores 
locally). The returned Python
-     * object is forwarded back into {@link #queryNormalized}. See
-     * https://github.com/apache/flink-agents/issues/844.
-     */
-    public Object normalizeEmbedding(float[] embedding) {
-        List<Float> embeddingList = new ArrayList<>(embedding.length);
-        for (float v : embedding) {
-            embeddingList.add(v);
-        }
-        Map<String, Object> kwargs = new HashMap<>();
-        kwargs.put("embeddings", embeddingList);
-        return adapter.callMethod(vectorStore, "_normalize_embeddings", 
kwargs);
-    }
-
-    /** Query with a pre-normalized embedding; numpy-free, so it stays on the 
async pool. */
-    @SuppressWarnings("unchecked")
-    public List<Document> queryNormalized(
-            Object normalizedEmbedding,
-            int limit,
-            @Nullable String collection,
-            @Nullable Map<String, Object> filters,
-            Map<String, Object> args) {
-        Map<String, Object> kwargs = new HashMap<>(args);
-        kwargs.put("embedding", normalizedEmbedding);
-        kwargs.put("limit", limit);
-        if (collection != null) {
-            kwargs.put("collection_name", collection);
-        }
-        if (filters != null) {
-            kwargs.put("filters", filters);
-        }
-        try (PythonObjectScope scope = new PythonObjectScope()) {
-            Object pythonDocuments =
-                    scope.own(adapter.callMethod(vectorStore, 
"_query_embedding", kwargs));
-            return adapter.fromPythonDocuments((List<PyObject>) 
pythonDocuments);
-        }
-    }
-
     @Override
     @SuppressWarnings("unchecked")
     public List<String> addEmbedding(
diff --git 
a/e2e-test/flink-agents-end-to-end-tests-resource-cross-language/src/test/java/org/apache/flink/agents/resource/test/VectorStoreCrossLanguageTest.java
 
b/e2e-test/flink-agents-end-to-end-tests-resource-cross-language/src/test/java/org/apache/flink/agents/resource/test/VectorStoreCrossLanguageTest.java
index 554462d9..eb5a8824 100644
--- 
a/e2e-test/flink-agents-end-to-end-tests-resource-cross-language/src/test/java/org/apache/flink/agents/resource/test/VectorStoreCrossLanguageTest.java
+++ 
b/e2e-test/flink-agents-end-to-end-tests-resource-cross-language/src/test/java/org/apache/flink/agents/resource/test/VectorStoreCrossLanguageTest.java
@@ -19,6 +19,7 @@
 package org.apache.flink.agents.resource.test;
 
 import org.apache.flink.agents.api.AgentsExecutionEnvironment;
+import org.apache.flink.agents.api.agents.AgentExecutionOptions;
 import org.apache.flink.api.java.functions.KeySelector;
 import org.apache.flink.streaming.api.datastream.DataStream;
 import org.apache.flink.streaming.api.datastream.DataStreamSource;
@@ -26,8 +27,9 @@ import 
org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
 import org.apache.flink.util.CloseableIterator;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Assumptions;
+import org.junit.jupiter.api.Timeout;
 import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.ValueSource;
+import org.junit.jupiter.params.provider.CsvSource;
 
 import java.io.IOException;
 import java.util.Map;
@@ -44,22 +46,26 @@ public class VectorStoreCrossLanguageTest {
     }
 
     @ParameterizedTest
-    @ValueSource(strings = {"JAVA", "PYTHON"})
-    public void testVectorStoreIntegration(String embeddingType) throws 
Exception {
+    @CsvSource({"JAVA, false", "JAVA, true", "PYTHON, false", "PYTHON, true"})
+    @Timeout(120)
+    public void testVectorStoreIntegration(String embeddingType, boolean 
ragAsync)
+            throws Exception {
         System.setProperty("EMBEDDING_TYPE", embeddingType);
         Assumptions.assumeTrue(ollamaReady, "Ollama Server information is not 
provided");
 
         StreamExecutionEnvironment env = 
StreamExecutionEnvironment.getExecutionEnvironment();
         env.setParallelism(1);
 
-        final DataStreamSource<String> inputStream = env.fromData("What is 
Apache Flink");
+        final DataStreamSource<String> inputStream =
+                env.fromData("What is Apache Flink", "What is ChromaDB");
 
         final AgentsExecutionEnvironment agentEnv =
                 AgentsExecutionEnvironment.getExecutionEnvironment(env);
+        agentEnv.getConfig().set(AgentExecutionOptions.RAG_ASYNC, ragAsync);
+        agentEnv.getConfig().set(AgentExecutionOptions.NUM_ASYNC_THREADS, 2);
 
         final DataStream<Object> outputStream =
-                agentEnv.fromDataStream(
-                                inputStream, (KeySelector<String, String>) 
value -> "orderKey")
+                agentEnv.fromDataStream(inputStream, (KeySelector<String, 
String>) value -> value)
                         .apply(new VectorStoreCrossLanguageAgent())
                         .toDataStream();
 
@@ -67,7 +73,11 @@ public class VectorStoreCrossLanguageTest {
 
         agentEnv.execute();
 
-        checkResult(results);
+        try (results) {
+            checkResult(results);
+            checkResult(results);
+            Assertions.assertFalse(results.hasNext(), "Unexpected extra 
retrieval response");
+        }
     }
 
     @SuppressWarnings("unchecked")
diff --git 
a/plan/src/main/java/org/apache/flink/agents/plan/actions/ContextRetrievalAction.java
 
b/plan/src/main/java/org/apache/flink/agents/plan/actions/ContextRetrievalAction.java
index 02610d08..900c149f 100644
--- 
a/plan/src/main/java/org/apache/flink/agents/plan/actions/ContextRetrievalAction.java
+++ 
b/plan/src/main/java/org/apache/flink/agents/plan/actions/ContextRetrievalAction.java
@@ -25,9 +25,7 @@ import org.apache.flink.agents.api.context.RunnerContext;
 import org.apache.flink.agents.api.event.ContextRetrievalRequestEvent;
 import org.apache.flink.agents.api.event.ContextRetrievalResponseEvent;
 import org.apache.flink.agents.api.resource.ResourceType;
-import org.apache.flink.agents.api.resource.python.PythonObjectScope;
 import org.apache.flink.agents.api.vectorstores.BaseVectorStore;
-import org.apache.flink.agents.api.vectorstores.Document;
 import org.apache.flink.agents.api.vectorstores.VectorStoreQuery;
 import org.apache.flink.agents.api.vectorstores.VectorStoreQueryResult;
 import org.apache.flink.agents.api.vectorstores.python.PythonVectorStore;
@@ -73,36 +71,27 @@ public class ContextRetrievalAction {
                             contextRetrievalRequestEvent.getQuery(),
                             contextRetrievalRequestEvent.getMaxResults());
 
-            final VectorStoreQueryResult result;
-            if (ragAsync && vectorStore instanceof PythonVectorStore) {
-                // A Python store's query path runs numpy, which can stall on 
the async pool
-                // (pemja keeps a single PyThreadState; numpy 
releasing/re-acquiring the GIL on a
-                // worker thread hangs intermittently — seen in CI, fine 
locally with spare cores).
-                // Keep only that numpy step on the mailbox thread; embed and 
query stay async.
-                result = queryPythonAsync((PythonVectorStore) vectorStore, 
vectorStoreQuery, ctx);
-            } else {
-                DurableCallable<VectorStoreQueryResult> callable =
-                        new DurableCallable<VectorStoreQueryResult>() {
-                            @Override
-                            public String getId() {
-                                return "rag-async";
-                            }
-
-                            @Override
-                            public Class<VectorStoreQueryResult> 
getResultClass() {
-                                return VectorStoreQueryResult.class;
-                            }
-
-                            @Override
-                            public VectorStoreQueryResult call() throws 
Exception {
-                                return vectorStore.query(vectorStoreQuery);
-                            }
-                        };
-                result =
-                        ragAsync
-                                ? ctx.durableExecuteAsync(callable).await()
-                                : ctx.durableExecute(callable);
-            }
+            DurableCallable<VectorStoreQueryResult> callable =
+                    new DurableCallable<VectorStoreQueryResult>() {
+                        @Override
+                        public String getId() {
+                            return "rag-async";
+                        }
+
+                        @Override
+                        public Class<VectorStoreQueryResult> getResultClass() {
+                            return VectorStoreQueryResult.class;
+                        }
+
+                        @Override
+                        public VectorStoreQueryResult call() throws Exception {
+                            return vectorStore.query(vectorStoreQuery);
+                        }
+                    };
+            final VectorStoreQueryResult result =
+                    ragAsync
+                            ? ctx.durableExecuteAsync(callable).await()
+                            : ctx.durableExecute(callable);
 
             ctx.sendEvent(
                     new ContextRetrievalResponseEvent(
@@ -111,65 +100,4 @@ public class ContextRetrievalAction {
                             result.getDocuments()));
         }
     }
-
-    /**
-     * Run a Python vector-store RAG query while keeping numpy off the async 
pool: embed async,
-     * normalize the embedding synchronously on the mailbox thread (numpy on a 
worker thread can
-     * stall under pemja's single PyThreadState), then query async with the 
pre-normalized vector.
-     * See https://github.com/apache/flink-agents/issues/844.
-     */
-    private static VectorStoreQueryResult queryPythonAsync(
-            PythonVectorStore store, VectorStoreQuery query, RunnerContext 
ctx) throws Exception {
-        final float[] embedding =
-                ctx.durableExecuteAsync(
-                                new DurableCallable<float[]>() {
-                                    @Override
-                                    public String getId() {
-                                        return "rag-embed";
-                                    }
-
-                                    @Override
-                                    public Class<float[]> getResultClass() {
-                                        return float[].class;
-                                    }
-
-                                    @Override
-                                    public float[] call() {
-                                        return 
store.embedQuery(query.getQueryText());
-                                    }
-                                })
-                        .await();
-
-        try (PythonObjectScope scope = new PythonObjectScope()) {
-            final Object normalized = 
scope.own(store.normalizeEmbedding(embedding));
-
-            final List<Document> documents =
-                    ctx.durableExecuteAsync(
-                                    new DurableCallable<List<Document>>() {
-                                        @Override
-                                        public String getId() {
-                                            return "rag-query";
-                                        }
-
-                                        @SuppressWarnings("unchecked")
-                                        @Override
-                                        public Class<List<Document>> 
getResultClass() {
-                                            return (Class<List<Document>>) 
(Class<?>) List.class;
-                                        }
-
-                                        @Override
-                                        public List<Document> call() {
-                                            return store.queryNormalized(
-                                                    normalized,
-                                                    query.getLimit(),
-                                                    query.getCollection(),
-                                                    query.getFilters(),
-                                                    store.getStoreKwargs());
-                                        }
-                                    })
-                            .await();
-
-            return new VectorStoreQueryResult(documents);
-        }
-    }
 }
diff --git a/python/flink_agents/api/vector_stores/vector_store.py 
b/python/flink_agents/api/vector_stores/vector_store.py
index 2cf04c49..d16d00c7 100644
--- a/python/flink_agents/api/vector_stores/vector_store.py
+++ b/python/flink_agents/api/vector_stores/vector_store.py
@@ -397,16 +397,6 @@ class BaseVectorStore(Resource, ABC):
             **kwargs: Vector store specific parameters.
         """
 
-    @staticmethod
-    def _normalize_embeddings(embeddings: list[float]) -> Any:
-        """Pre-process a query embedding before the search call.
-
-        Hook for backends whose query path performs CPU/numpy work that must 
run
-        on the mailbox thread rather than an async cross-language worker (see 
the
-        ChromaDB override). Default is identity.
-        """
-        return embeddings
-
     @abstractmethod
     def _query_embedding(
         self,
diff --git 
a/python/flink_agents/integrations/vector_stores/chroma/chroma_vector_store.py 
b/python/flink_agents/integrations/vector_stores/chroma/chroma_vector_store.py
index cab7ec3d..e65ba922 100644
--- 
a/python/flink_agents/integrations/vector_stores/chroma/chroma_vector_store.py
+++ 
b/python/flink_agents/integrations/vector_stores/chroma/chroma_vector_store.py
@@ -22,7 +22,6 @@ from typing import Any, Dict, Generator, List
 import chromadb
 from chromadb import ClientAPI as ChromaClient
 from chromadb import CloudClient
-from chromadb.api.types import normalize_embeddings
 from chromadb.config import Settings
 from pydantic import Field
 from typing_extensions import override
@@ -317,20 +316,6 @@ class ChromaVectorStore(CollectionManageableVectorStore):
             metadatas=[doc.metadata for doc in documents],
         )
 
-    @staticmethod
-    @override
-    def _normalize_embeddings(embeddings: List[float]) -> Any:
-        """Convert the raw embedding to chroma's numpy form on the caller's 
thread.
-
-        chroma's query normally runs this np.array conversion internally. numpy
-        releases and re-acquires the GIL during the copy, which can stall on an
-        async pemja worker thread (pemja keeps a single PyThreadState) — seen 
as a
-        hang in CI, benign locally with spare cores. Running it here lets the
-        mailbox thread do the numpy step, so the async query sees a ready 
ndarray.
-        See https://github.com/apache/flink-agents/issues/844.
-        """
-        return normalize_embeddings([embeddings])[0]
-
     @override
     def _query_embedding(
         self,
@@ -340,9 +325,6 @@ class ChromaVectorStore(CollectionManageableVectorStore):
         filters: Dict[str, Any] | None = None,
         **kwargs: Any,
     ) -> List[Document]:
-        # ``embedding`` may be a pre-normalized ndarray (async path) or a raw 
list
-        # (sync path); chroma takes the ndarray branch for the former, 
avoiding any
-        # numpy work on this thread.
         collection = self._resolve_collection(collection_name, kwargs)
         results = collection.query(
             query_embeddings=[embedding],

Reply via email to