Skip to main content
Semantic search matches by meaning: “time off” can find a document about “annual leave.” Keyword search matches the words themselves, which helps with an error code such as E_AUTH_429. HydraDB combines both by default; this is called hybrid search. BM25 is the keyword-ranking method used in that combination.
POST /query is the unified retrieval endpoint. Two parameters decide what runs:
  • type picks the store: "knowledge" (Knowledge), "memory" (user-scoped Memories), or "all" (both from the same scope, merged and re-ranked together).
  • query_by picks the retrieval method: "hybrid" (semantic + BM25, the default) or "text" (BM25 only, with operator: "or" | "and" | "phrase", default "or").

Why pure semantic search breaks

Pure vector search can miss important production constraints:
  • Exact identifiers such as E_AUTH_429 or payments-worker-v4 may be generalized away.
  • A project name can collide with a normal word, like strawberry the project vs strawberry the fruit.
  • Old and new documents can look equally relevant without recency or metadata signals.
  • Different users can need different context for the same query.
  • Relationship questions need graph context, not only similar text chunks.
That is why HydraDB exposes semantic retrieval through query_by: "hybrid" inside the unified /query endpoint rather than as a separate pure-vector mode.

The alpha parameter

alpha controls the semantic versus BM25 keyword blend when query_by: "hybrid". Higher values lean semantic; lower values lean on keywords. Start with the API default (0.8; "auto" also resolves to 0.8) and tune from observed results. If users query for exact IDs and get loosely related content, lower alpha. If they ask broad conceptual questions and get sparse results, raise it. alpha applies only to query_by: "hybrid"; it is ignored for "text".

Query request example

metadata_filters are exact constraints that run before ranking and are re-checked after the matching passages are loaded. Use them whenever the query has a scope that should not be violated. Top-level keys match metadata and support equals, contains, and contains_any (no range or fuzzy match); nest under additional_metadata to filter free-form per-document fields. The example above uses one to keep retrieval inside the phoenix project.

More recipes

Technical lookup

Lower alpha when names, IDs, and literal strings matter.

Exact phrase query

Switch to query_by: "text" with operator: "phrase" when a literal match is the point of the query.

Reading the response

POST /query returns ranked chunks and source metadata, not an answer. A typical application flow is:
  1. Call POST /query with the right type and query_by for the query.
  2. Keep the chunks that are relevant enough for your use case.
  3. Format chunk_content, source titles, and graph context into a prompt.
  4. Ask your LLM to answer using only that context.
See How to Use API Results for complete context-building examples.