Skip to content

bug(vector_stores/valkey): search score hardcoded for cosine, breaks L2 ranking #7229

Description

@ktz03

Description

Same class of bug as #6546 / #6547, but in the Valkey vector store.

ValkeyDB._process_search_results hardcodes:

score = max(0.0, 1.0 - raw_distance)

That mapping is only correct for COSINE (and IP after Redis/Valkey's 1/(1+IP) transform). For L2, distance is unbounded, so any hit with distance > 1 collapses to 0.0 and ranking / score thresholds break.

Additionally:

  1. _create_index always creates the index with hardcoded "COSINE", ignoring any configured metric.
  2. create_col(..., distance="L2"|"IP") already accepts a metric for FT.CREATE, but does not persist it on self, so subsequent search still scores as cosine.

Steps to Reproduce

  1. Create a Valkey collection with L2:
    store.create_col(name="demo", vector_size=768, distance="L2")
  2. Insert vectors and search.
  3. Observe returned scores: distant neighbors with L2 distance > 1 become 0.0 under 1 - distance.

Expected Behavior

Additional Context

Activity

  1. ktz03 commented on Sep 5, 2026

    @ktz03
    Author

    Hi maintainers — this is the Valkey sibling of #6546. Could you please add the accepted label so a PR can be reviewed? PR incoming that mirrors #6547.

  2. ktz03 commented on Sep 5, 2026

    @ktz03
    Author

    Hi @kartik-mem0 — this is the Valkey sibling of #6546 / #6547 (same hardcoded 1 - distance collapsing L2 scores).

    Could you please add the accepted label when you have a moment? PR #7230 is ready and will auto-reopen once the issue is accepted.

  3. ktz03 commented on Sep 5, 2026

    @ktz03
    Author

    Also noting a third sibling in the same family: Vertex AI Vector Search still hardcodes 1 - distance in three places (_parse_output / search / get). Filed as a follow-up — will keep PRs sequential so review stays small.

  4. ktz03 commented on Sep 8, 2026

    @ktz03
    Author

    Friendly follow-up on the Valkey sibling of the already-traced S3 case.

    When you have a moment, could you add accepted here so #7230 can auto-reopen into the review queue? Happy to rebase or adjust anything needed.

  5. blazingretinol commented on Sep 25, 2026

    @blazingretinol
    Contributor

    Confirmed. Pointing collection_name at an existing Valkey index built with L2 (or calling create_col with distance L2) still scores with the cosine formula, so a real match with distance over 1 collapses to a score of 0 and gets silently dropped by the default search threshold.

    Cause is in mem0/vector_stores/valkey.py: _create_index (line 196) reuses an existing index without checking its metric, and _process_search_results (line 400) always applies max(0, 1 - distance), which only holds for cosine. Reproduced against a real Valkey Search container.

    PR #7230 persists a declared distance metric, so create_col with an explicit metric now scores correctly. An index reused without anyone explicitly declaring its metric still scores wrong after that fix.

  6. added
    bugSomething isn't working
    P1-highBlocks significant use case, high demand
    acceptedA maintainer has agreed to this change. Required before a PR is reviewed.
    on Sep 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1-highBlocks significant use case, high demandacceptedA maintainer has agreed to this change. Required before a PR is reviewed.bugSomething isn't workingsdk-pythonPython SDK specificvector-storeVector store backends (Qdrant, PGVector, Redis, etc.)

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions