fix: support dense_vector from ES fields response (ES 9.x compatibility) (#13972)

fix: support dense_vector from ES fields response (ES 9.x compatibility)

- [x] Bug Fix (non-breaking change which fixes an issue)
- [x] Configuration Chore (non-breaking change which updates
configuration)


## Summary by CodeRabbit

* **Bug Fixes**
* More accurate handling and unwrapping of dense-vector fields so
returned values have correct shapes.
* Field selection reliably limits returned data and falls back to
alternate result locations when needed.
* Use of consistent result IDs and tolerant handling when score values
are missing.

* **Chores / Configuration**
* Increased build memory and adjusted build-time flags for the frontend
build.
* Simplified runtime model/GPU checks and removed an automated runtime
GPU-install attempt.

* **Build Fixes**
* `web/vite.config.ts`: make `build.minify` and `build.sourcemap`
respect `VITE_MINIFY` and `VITE_BUILD_SOURCEMAP` env vars from
Dockerfile instead of hardcoding `terser` and `true`.

* **Environment**
* Allow stack version override and default the runtime image tag to
"latest".

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Correct unwrapping of dense-vector fields and reliable field selection
with fallback locations.
* Consistent use of hit-level IDs and tolerant handling when score
values are missing.

* **Chores / Configuration**
* Increased frontend build memory and added build-time minify/sourcemap
flags; build minification and sourcemap now configurable.
* Removed runtime GPU detection for model initialization; force CPU
initialization.

* **Environment**
* Allow stack version override and default runtime image tag to
"latest".

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Zhichang Yu
2026-04-09 17:44:13 +08:00
committed by GitHub
parent 107fe6cf90
commit b7744e053e
50 changed files with 142 additions and 124 deletions

View File

@@ -253,7 +253,18 @@ class ESConnection(ESConnectionBase):
if limit > 0 and not use_search_after:
s = s[offset:offset + limit]
# Filter _source to only requested fields for efficiency, and add vector
# fields to "fields" param so they appear in hit.fields when ES 9.x
# exclude_source_vectors is enabled (dense_vector not in _source).
if select_fields:
s = s.source(select_fields)
q = s.to_dict()
# ES 9.x: dense_vector fields excluded from _source; request them via fields.
# Note: knn does NOT have a "fields" parameter - adding it inside the knn
# object causes BadRequestError on ES 9.x. We add "fields" at top level.
vector_fields = [f for f in (select_fields or []) if f.endswith("_vec")]
if vector_fields:
q["fields"] = vector_fields
self.logger.debug(f"ESConnection.search {str(index_names)} query: " + json.dumps(q))
for i in range(ATTEMPT_TIME):
@@ -565,8 +576,24 @@ class ESConnection(ESConnectionBase):
res_fields = {}
if not fields:
return {}
for d in self._get_source(res):
m = {n: d.get(n) for n in fields if d.get(n) is not None}
hits = res.get("hits", {}).get("hits", [])
for hit in hits:
doc_id = hit.get("_id")
d = hit.get("_source", {})
# Also extract fields from ES "fields" response (used by dense_vector in ES 9.x)
hit_fields = hit.get("fields", {})
m = {}
for n in fields:
# First check _source
if d.get(n) is not None:
m[n] = d.get(n)
# Then check fields (ES 9.x stores dense_vector here, not in _source)
elif n in hit_fields:
vals = hit_fields[n]
# ES fields response wraps dense_vector in 2 levels: [[v1,v2,...]] -> [v1,v2,...]
if isinstance(vals, list) and len(vals) == 1:
vals = vals[0]
m[n] = vals
for n, v in m.items():
if isinstance(v, list):
m[n] = v
@@ -580,5 +607,5 @@ class ESConnection(ESConnectionBase):
# m[n] = remove_redundant_spaces(m[n])
if m:
res_fields[d["id"]] = m
res_fields[doc_id] = m
return res_fields