> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hydradb.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Semantic Search & Retrieval

> How semantic, keyword bm25, graph, and metadata signals work together in HydraDB query.

Semantic search is useful because it retrieves by meaning instead of exact wording. It is also incomplete on its own: production agents need exact matches, freshness, scope, database isolation, metadata filters, and graph relationships. HydraDB query combines those signals so you can retrieve context that is useful, not just similar.

***

## Semantic vs Keyword BM25

| Query Type   | Finds                              | Best For                                                      |
| ------------ | ---------------------------------- | ------------------------------------------------------------- |
| Semantic     | Text with similar meaning          | Natural-language questions, paraphrases, conceptual lookup    |
| Keyword BM25 | Text with matching tokens          | Error codes, identifiers, names, SKUs, exact phrases          |
| Graph        | Related entities and relationships | Multi-hop questions, dependencies, ownership, project context |

`POST /query` is the unified retrieval endpoint. Two parameters decide what runs:

* **`type`** picks the collection: `"knowledge"` (Knowledge), `"memory"` (user-scoped Memories), or `"all"` (both, 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"`).

***

## 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-vs-keyword-bm25 blend when `query_by: "hybrid"`. Higher values lean semantic. Lower values lean keyword bm25.

| `alpha` | Behavior                        | Use When                                          |
| ------- | ------------------------------- | ------------------------------------------------- |
| `1.0`   | Semantic-heavy                  | Conceptual questions and paraphrases              |
| `0.8`   | Default semantic-leaning hybrid | Most agent query workflows                        |
| `0.5`   | Balanced                        | Mixed natural language and exact terms            |
| `0.2`   | Keyword BM25-leaning            | Queries with product names, error strings, or IDs |
| `0.0`   | Keyword BM25-heavy              | Debugging exact-match behavior                    |

Start with the API default (`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

<CodeGroup>
  ```bash cURL theme={"dark"}
  curl -X POST 'https://api.hydradb.com/query' \
    -H "Authorization: Bearer $HYDRA_DB_API_KEY" \
    -H "API-Version: 2" \
    -H "Content-Type: application/json" \
    -d '{
      "database": "acme",
      "collection": "team-mobile",
      "query": "How do we rotate API keys?",
      "type": "knowledge",
      "query_by": "hybrid",
      "max_results": 8,
      "alpha": 0.8,
      "recency_bias": 0.2,
      "graph_context": true,
      "metadata_filters": {
        "project": "phoenix"
      }
    }'
  ```

  ```typescript TypeScript SDK theme={"dark"}
  const result = await client.query({
    database: "acme",
    collection: "team-mobile",
    query: "How do we rotate API keys?",
    type: "knowledge",
    queryBy: "hybrid",
    maxResults: 8,
    alpha: 0.8,
    recencyBias: 0.2,
    graphContext: true,
    metadataFilters: { project: "phoenix" },
  });
  ```

  ```python Python SDK theme={"dark"}
  result = client.query(
      database="acme",
      collection="team-mobile",
      query="How do we rotate API keys?",
      type="knowledge",
      query_by="hybrid",
      max_results=8,
      alpha=0.8,
      recency_bias=0.2,
      graph_context=True,
      metadata_filters={"project": "phoenix"},
  )
  ```
</CodeGroup>

`metadata_filters` are exact constraints that run before ranking and are re-checked after hydration. Use them whenever the query has a scope that should not be violated. Top-level keys match `metadata`; nest under `additional_metadata` to filter free-form per-document fields.

***

## Practical Recipes

### General Retrieval

Use the default semantic-leaning blend for natural-language questions over documents.

<CodeGroup>
  ```bash cURL theme={"dark"}
  curl -X POST 'https://api.hydradb.com/query' \
    -H "Authorization: Bearer $HYDRA_DB_API_KEY" \
    -H "API-Version: 2" \
    -H "Content-Type: application/json" \
    -d '{
      "database": "acme",
      "query": "How does onboarding work?",
      "type": "knowledge",
      "query_by": "hybrid",
      "max_results": 8,
      "alpha": 0.8
    }'
  ```

  ```typescript TypeScript SDK theme={"dark"}
  const result = await client.query({
    database: "acme",
    query: "How does onboarding work?",
    type: "knowledge",
    queryBy: "hybrid",
    maxResults: 8,
    alpha: 0.8,
  });
  ```

  ```python Python SDK theme={"dark"}
  result = client.query(
      database="acme",
      query="How does onboarding work?",
      type="knowledge",
      query_by="hybrid",
      max_results=8,
      alpha=0.8,
  )
  ```
</CodeGroup>

### Technical Lookup

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

<CodeGroup>
  ```bash cURL theme={"dark"}
  curl -X POST 'https://api.hydradb.com/query' \
    -H "Authorization: Bearer $HYDRA_DB_API_KEY" \
    -H "API-Version: 2" \
    -H "Content-Type: application/json" \
    -d '{
      "database": "acme",
      "query": "TimeoutError in payments-worker v4.2.1",
      "type": "knowledge",
      "query_by": "hybrid",
      "max_results": 5,
      "alpha": 0.3,
      "recency_bias": 0.4
    }'
  ```

  ```typescript TypeScript SDK theme={"dark"}
  const result = await client.query({
    database: "acme",
    query: "TimeoutError in payments-worker v4.2.1",
    type: "knowledge",
    queryBy: "hybrid",
    maxResults: 5,
    alpha: 0.3,
    recencyBias: 0.4,
  });
  ```

  ```python Python SDK theme={"dark"}
  result = client.query(
      database="acme",
      query="TimeoutError in payments-worker v4.2.1",
      type="knowledge",
      query_by="hybrid",
      max_results=5,
      alpha=0.3,
      recency_bias=0.4,
  )
  ```
</CodeGroup>

### Scoped Retrieval

Use metadata filters to keep retrieval inside a project, team, customer, data class, or source.

<CodeGroup>
  ```bash cURL theme={"dark"}
  curl -X POST 'https://api.hydradb.com/query' \
    -H "Authorization: Bearer $HYDRA_DB_API_KEY" \
    -H "API-Version: 2" \
    -H "Content-Type: application/json" \
    -d '{
      "database": "acme",
      "collection": "team-mobile",
      "query": "What is the current sprint status?",
      "type": "knowledge",
      "query_by": "hybrid",
      "metadata_filters": {
        "project": "phoenix"
      }
    }'
  ```

  ```typescript TypeScript SDK theme={"dark"}
  const result = await client.query({
    database: "acme",
    collection: "team-mobile",
    query: "What is the current sprint status?",
    type: "knowledge",
    queryBy: "hybrid",
    metadataFilters: { project: "phoenix" },
  });
  ```

  ```python Python SDK theme={"dark"}
  result = client.query(
      database="acme",
      collection="team-mobile",
      query="What is the current sprint status?",
      type="knowledge",
      query_by="hybrid",
      metadata_filters={"project": "phoenix"},
  )
  ```
</CodeGroup>

### Exact Phrase Query

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

<CodeGroup>
  ```bash cURL theme={"dark"}
  curl -X POST 'https://api.hydradb.com/query' \
    -H "Authorization: Bearer $HYDRA_DB_API_KEY" \
    -H "API-Version: 2" \
    -H "Content-Type: application/json" \
    -d '{
      "database": "acme",
      "query": "mechanical engineer",
      "type": "knowledge",
      "query_by": "text",
      "operator": "phrase",
      "max_results": 10
    }'
  ```

  ```typescript TypeScript SDK theme={"dark"}
  const result = await client.query({
    database: "acme",
    query: "mechanical engineer",
    type: "knowledge",
    queryBy: "text",
    operator: "phrase",
    maxResults: 10,
  });
  ```

  ```python Python SDK theme={"dark"}
  result = client.query(
      database="acme",
      query="mechanical engineer",
      type="knowledge",
      query_by="text",
      operator="phrase",
      max_results=10,
  )
  ```
</CodeGroup>

***

## 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](/essentials/v2/api-results) for complete context-building examples.

***

## Mental Model

Semantic search finds text that means the same thing. Keyword BM25 search finds text that says the same thing. Graph context finds connected entities. Metadata filters decide what is allowed to be queried. `POST /query` combines all four behind one endpoint via `type`, `query_by`, `metadata_filters`, and `graph_context` so your agents get context that is scoped, relevant, and explainable.

***

## Related

* [Query](/essentials/v2/query) - full parameter reference and parallel query patterns
* [Context Graphs](/essentials/v2/context-graphs) - how graph context enriches retrieval
* [Metadata](/essentials/v2/metadata) - designing filterable schemas
* [How to Use API Results](/essentials/v2/api-results) - turning the response into an LLM prompt
