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

# Score Normalize

> Rescale document scores to a common range for consistent comparison

<Frame>
  <img src="https://mintcdn.com/mixpeek/TmiAqiYj-LwmWL2a/assets/retrievers/score-normalize.svg?fit=max&auto=format&n=TmiAqiYj-LwmWL2a&q=85&s=eaecf3f5c9379dc1d76f3e6044d70b86" alt="Score normalize stage showing score rescaling from raw to normalized range" width="800" height="300" data-path="assets/retrievers/score-normalize.svg" />
</Frame>

The Score Normalize stage rescales document scores using statistical normalization methods, enabling meaningful comparison across different scoring sources and consistent downstream thresholding.

<Note>
  **Stage Category**: SORT (Rescales scores)

  **Transformation**: N documents → N documents (same order, normalized scores)
</Note>

## When to Use

| Use Case                   | Description                                        |
| -------------------------- | -------------------------------------------------- |
| **Hybrid search fusion**   | Normalize text and vector scores before combining  |
| **Score thresholding**     | Set consistent cutoffs across different retrievers |
| **Cross-model comparison** | Make scores from different models comparable       |
| **Probability ranking**    | Convert scores to probability distribution         |
| **Multi-stage pipelines**  | Normalize between reranking stages                 |

## When NOT to Use

| Scenario                      | Recommended Alternative           |
| ----------------------------- | --------------------------------- |
| Reordering by relevance       | `sort_relevance`                  |
| Reranking with cross-encoders | `rerank`                          |
| Filtering by score threshold  | `attribute_filter` on score field |
| Single scoring source         | Scores are already comparable     |

## Parameters

| Parameter      | Type   | Default   | Description                                                 |
| -------------- | ------ | --------- | ----------------------------------------------------------- |
| `method`       | string | `min_max` | Normalization method: `min_max`, `z_score`, `softmax`, `l2` |
| `score_field`  | string | `score`   | Field containing the score to normalize                     |
| `output_field` | string | `null`    | Write normalized score to this field (preserves original)   |
| `min_value`    | float  | `null`    | Custom minimum for min\_max (uses actual min if null)       |
| `max_value`    | float  | `null`    | Custom maximum for min\_max (uses actual max if null)       |

## Normalization Methods

| Method    | Formula                 | Output Range  | Best For                 |
| --------- | ----------------------- | ------------- | ------------------------ |
| `min_max` | (x - min) / (max - min) | \[0, 1]       | Bounded comparison       |
| `z_score` | (x - mean) / std        | (-∞, +∞)      | Statistical thresholding |
| `softmax` | exp(x) / Σexp           | (0, 1), sum=1 | Probability distribution |
| `l2`      | x / ‖x‖₂                | \[-1, 1]      | Geometric comparison     |

## Configuration Examples

<CodeGroup>
  ```json Min-Max to [0,1] theme={null}
  {
    "stage_name": "score_normalize",
    "stage_type": "sort",
    "config": {
      "stage_id": "score_normalize",
      "parameters": {
        "method": "min_max",
        "score_field": "score"
      }
    }
  }
  ```

  ```json Z-Score with Separate Output theme={null}
  {
    "stage_name": "score_normalize",
    "stage_type": "sort",
    "config": {
      "stage_id": "score_normalize",
      "parameters": {
        "method": "z_score",
        "score_field": "score",
        "output_field": "z_score"
      }
    }
  }
  ```

  ```json Softmax Probability theme={null}
  {
    "stage_name": "score_normalize",
    "stage_type": "sort",
    "config": {
      "stage_id": "score_normalize",
      "parameters": {
        "method": "softmax",
        "score_field": "score",
        "output_field": "probability"
      }
    }
  }
  ```

  ```json Custom Range Bounds theme={null}
  {
    "stage_name": "score_normalize",
    "stage_type": "sort",
    "config": {
      "stage_id": "score_normalize",
      "parameters": {
        "method": "min_max",
        "min_value": 0.0,
        "max_value": 1.0
      }
    }
  }
  ```
</CodeGroup>

<Tip>
  Use `output_field` to preserve the original score alongside the normalized value. This is useful for debugging or when you need both raw and normalized scores downstream.
</Tip>

## Performance

| Metric         | Value                                |
| -------------- | ------------------------------------ |
| **Latency**    | \< 1ms                               |
| **Memory**     | O(N) for score array                 |
| **Cost**       | Free                                 |
| **Complexity** | O(N) (two passes: stats + normalize) |

## Common Pipeline Patterns

### Hybrid Search Fusion

```json theme={null}
[
  {
    "stage_name": "feature_search",
    "stage_type": "filter",
    "config": {
      "stage_id": "feature_search",
      "parameters": {
        "searches": [{"feature_uri": "mixpeek://text_extractor@v1/multilingual_e5_large_instruct_v1", "query": {"input_mode": "text", "value": "{{INPUT.query}}"}, "top_k": 50}],
        "final_top_k": 50
      }
    }
  },
  {
    "stage_name": "score_normalize",
    "stage_type": "sort",
    "config": {
      "stage_id": "score_normalize",
      "parameters": {
        "method": "min_max",
        "score_field": "score"
      }
    }
  },
  {
    "stage_name": "rerank",
    "stage_type": "sort",
    "config": {
      "stage_id": "rerank",
      "parameters": {
        "inference_name": "BAAI__bge_reranker_v2_m3",
        "query": "{{INPUT.query}}",
        "document_field": "content"
      }
    }
  }
]
```

### Score Thresholding After Normalization

```json theme={null}
[
  {
    "stage_name": "feature_search",
    "stage_type": "filter",
    "config": {
      "stage_id": "feature_search",
      "parameters": {
        "searches": [{"feature_uri": "mixpeek://text_extractor@v1/multilingual_e5_large_instruct_v1", "query": {"input_mode": "text", "value": "{{INPUT.query}}"}, "top_k": 100}],
        "final_top_k": 100
      }
    }
  },
  {
    "stage_name": "score_normalize",
    "stage_type": "sort",
    "config": {
      "stage_id": "score_normalize",
      "parameters": {
        "method": "min_max"
      }
    }
  },
  {
    "stage_name": "attribute_filter",
    "stage_type": "filter",
    "config": {
      "stage_id": "attribute_filter",
      "parameters": {
        "AND": [
          {"field": "score", "operator": "gte", "value": 0.5}
        ]
      }
    }
  }
]
```

## Error Handling

| Error               | Behavior                                                   |
| ------------------- | ---------------------------------------------------------- |
| Single document     | min\_max returns 1.0; z\_score returns 0.0                 |
| All same scores     | min\_max returns 1.0 for all; z\_score returns 0.0 for all |
| Score field missing | Treated as 0.0                                             |
| Non-numeric score   | Treated as 0.0                                             |

## Related

* [Sort Relevance](/retrieval/stages/sort-relevance) - Reorder by relevance scores
* [Rerank](/retrieval/stages/rerank) - Re-score with cross-encoder models
* [Sort Attribute](/retrieval/stages/sort-attribute) - Sort by any metadata field
