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

# Boost with Signals Stage

export const schema = {
  "type": "object",
  "title": "Boost with Signals",
  "description": "Boosts search results at query time using item-item recommendation scores derived from user interaction signals.",
  "required": ["boostingMethod", "boostingParam"],
  "properties": {
    "skip": {
      "type": "boolean",
      "title": "Skip This Stage",
      "description": "Controls whether this stage executes during pipeline processing at runtime. When set to `true`, the stage is completely bypassed and documents pass through unchanged to the next stage. Useful for A/B testing, gradual rollouts, or temporarily disabling a stage without removing it from the pipeline.",
      "default": false,
      "hints": ["advanced"]
    },
    "label": {
      "type": "string",
      "title": "Label",
      "description": "Human-readable identifier displayed in the Fusion Admin UI, monitoring dashboards, and log messages. Use descriptive labels like `Parse Product PDFs` to aid debugging and team collaboration. Labels appear in performance metrics and error reports, making it easier to identify which stage failed.",
      "hints": ["advanced"],
      "maxLength": 255
    },
    "condition": {
      "type": "string",
      "title": "Condition",
      "description": "JavaScript expression evaluated at runtime on each document to conditionally execute this stage. The expression must return `true` to execute or `false` to skip. Access document fields using `doc.getFieldValue('fieldName')` and request parameters via `request.getFirstParam('paramName')`. For example, `doc.getFieldValue('type') === 'premium'` executes this stage only for premium content.",
      "hints": ["code", "code/javascript", "advanced"]
    },
    "legacy": {
      "type": "boolean",
      "title": "Legacy",
      "description": "When `true`, this stage operates in legacy mode only.",
      "hints": ["readonly", "hidden"]
    },
    "asyncConfig": {
      "type": "object",
      "title": "Asynchronous Execution Config",
      "required": ["enabled", "asyncId"],
      "properties": {
        "enabled": {
          "type": "boolean",
          "title": "Enable Async Execution",
          "description": "Run the expensive data loading or processing part of this stage in a separate thread allowing the pipeline to continue executing. The results of this asynchronous execution can be merged into the pipeline request using a downstream Merge Async Results stage.",
          "default": false
        },
        "asyncId": {
          "type": "string",
          "title": "Async ID",
          "description": "A unique value to use as reference in downstream Merge Async Results stages."
        }
      }
    },
    "numRecommendations": {
      "type": "integer",
      "title": "Number of Recommendations",
      "description": "Sets the number of documents the main query returns.",
      "default": 10
    },
    "numSignals": {
      "type": "integer",
      "title": "Number of Signals",
      "description": "Sets the number of signals processed when computing recommended items.",
      "default": 100
    },
    "aggrType": {
      "type": "string",
      "title": "Aggregation Type",
      "default": "click@doc_id,filters,query"
    },
    "boostId": {
      "type": "string",
      "title": "Solr Field to Boost On",
      "description": "Specifies the Solr field used as the identifier when applying recommendation boosts.",
      "default": "id"
    },
    "boostingMethod": {
      "type": "string",
      "title": "Boost Method",
      "description": "Specifies the boost method. Use `query-parser` when `defType` is not `edismax` for the main query.",
      "enum": ["query-param", "query-parser"],
      "default": "query-param",
      "hints": ["advanced"]
    },
    "boostingParam": {
      "type": "string",
      "title": "Boost Param",
      "description": "Specifies whether `boost` multiplies scores by boost values or `bq` adds optional clauses to the main query.",
      "enum": ["boost", "bq"],
      "default": "boost",
      "hints": ["advanced"]
    },
    "scaleRange": {
      "type": "object",
      "title": "Scale Boosts",
      "description": "Scales boost values to a specified `[min, max]` range before applying them.",
      "required": ["scaleMin", "scaleMax"],
      "properties": {
        "scaleMin": {
          "type": "number",
          "title": "Minimum value of the scale range",
          "description": "Threshold or limit value for minimum value of the scale range. Values outside this threshold trigger different processing behavior. Numeric value with valid range determined by operational context."
        },
        "scaleMax": {
          "type": "number",
          "title": "Maximum value of the scale range",
          "description": "Threshold or limit value for maximum value of the scale range. Values outside this threshold trigger different processing behavior. Numeric value with valid range determined by operational context."
        }
      },
      "hints": ["advanced"]
    },
    "queryParams": {
      "type": "array",
      "title": "Solr Query parameters",
      "description": "Specifies additional parameters for querying the signal aggregation collection.",
      "default": [{
        "key": "qf",
        "value": "query_t"
      }, {
        "key": "pf",
        "value": "query_t^50"
      }, {
        "key": "pf",
        "value": "query_t~3^20"
      }, {
        "key": "pf2",
        "value": "query_t^20"
      }, {
        "key": "pf2",
        "value": "query_t~3^10"
      }, {
        "key": "pf3",
        "value": "query_t^10"
      }, {
        "key": "pf3",
        "value": "query_t~3^5"
      }, {
        "key": "mm",
        "value": "50%"
      }, {
        "key": "boost",
        "value": "map(query({!field f=query_s v=$q}),0,0,1,20)"
      }, {
        "key": "defType",
        "value": "edismax"
      }, {
        "key": "sort",
        "value": "score desc, weight_d desc"
      }, {
        "key": "fq",
        "value": "weight_d:[* TO *]"
      }],
      "hints": ["advanced"],
      "items": {
        "type": "object",
        "required": ["key"],
        "properties": {
          "key": {
            "type": "string",
            "title": "Parameter Name"
          },
          "value": {
            "type": "string",
            "title": "Parameter Value"
          }
        }
      }
    },
    "rollupField": {
      "type": "string",
      "title": "Rollup Field",
      "description": "Specifies the field name used to roll up recommendation scores across related documents.",
      "hints": ["advanced"]
    },
    "rollupWeightField": {
      "type": "string",
      "title": "Rollup weight field",
      "description": "Specifies the field name containing the rollup weight value.",
      "hints": ["advanced"]
    },
    "rollupWeightStrategy": {
      "type": "string",
      "title": "Rollup weight strategy",
      "description": "Specifies the strategy for combining weights across grouped documents. Use `max` to take the highest weight or `sum` to add all weights.",
      "enum": ["sum", "max"],
      "hints": ["advanced"]
    },
    "weightExpression": {
      "type": "string",
      "title": "Final Boost Weight Expression",
      "description": "Specifies an optional expression to compute the final boost weight from Solr response fields such as `score` and `weight_d`. Set to `weight_d` for behavior matching older versions.",
      "default": "math:log(weight_d + 1) + 10 * math:log(score+1)"
    },
    "contextKey": {
      "type": "string",
      "title": "Document Weights Context Key",
      "description": "Specifies the context key under which the `docId:weight` boost map is saved."
    },
    "queryParamToBoost": {
      "type": "string",
      "title": "Query Param",
      "description": "Specifies the request parameter containing the query to boost. Defaults to `q`.",
      "default": "q"
    },
    "includeEnrichedQuery": {
      "type": "boolean",
      "title": "Include Enriched Query",
      "description": "When enabled, combines the user's original query with output from query enrichment stages such as the tagger to expand recall for the boost lookup. May modify the `mm` parameter to accommodate additional terms."
    }
  },
  "category": "Results Relevancy",
  "categoryPriority": 7,
  "unsafe": false
};

export const SchemaParamFields = ({schema}) => {
  const sanitize = str => {
    if (typeof str !== "string") return str;
    return str.replace(/^"(.*)"$/s, "$1").replace(/\\/g, "").replace(/"/g, "'");
  };
  const renderMd = str => {
    const s = sanitize(str);
    const text = (/[.!?]\)*$/).test(s) ? s : `${s}.`;
    return text.split(/(\*\*[^*]+\*\*|_[^_]+_|`[^`]+`)/g).map((part, i) => {
      if (part.startsWith("**")) return <strong key={i}>{part.slice(2, -2)}</strong>;
      if (part.startsWith("_")) return <em key={i}>{part.slice(1, -1)}</em>;
      if (part.startsWith("`")) return <code key={i}>{part.slice(1, -1)}</code>;
      return part;
    });
  };
  const {description, properties = {}, required: requiredProps = []} = schema;
  const visibleProps = useMemo(() => Object.entries(properties).filter(([, prop]) => !prop.hints?.includes("hidden")), [properties]);
  const renderProp = ([name, prop]) => {
    const isRequired = requiredProps.includes(name);
    const hasDefault = prop.default !== undefined;
    const rawDefault = prop.default;
    const hints = prop.hints || [];
    const isComplexDefault = hasDefault && (typeof rawDefault === "object" || typeof rawDefault === "string" && (rawDefault.length > 20 || rawDefault.includes('"')));
    const postBadges = [];
    if (prop.title) {
      postBadges.push(<><span className="text-stone-400 dark:text-stone-500">API property: </span>{name}</>);
    }
    const constraints = [];
    if (prop.minimum !== undefined && prop.maximum !== undefined) {
      constraints.push(`Range: ${prop.minimum} – ${prop.maximum}`);
    } else if (prop.minimum !== undefined) {
      constraints.push(`Min: ${prop.minimum}`);
    } else if (prop.maximum !== undefined) {
      constraints.push(`Max: ${prop.maximum}`);
    }
    if (prop.minLength !== undefined && prop.maxLength !== undefined) {
      constraints.push(`Length: ${prop.minLength} – ${prop.maxLength}`);
    } else if (prop.minLength !== undefined) {
      constraints.push(`Min length: ${prop.minLength}`);
    } else if (prop.maxLength !== undefined) {
      constraints.push(`Max length: ${prop.maxLength}`);
    }
    const fieldProps = {
      key: name,
      body: prop.title || name,
      type: prop.type,
      ...postBadges.length > 0 && ({
        post: postBadges
      }),
      ...isRequired && ({
        required: true
      }),
      ...!isComplexDefault && hasDefault ? {
        default: sanitize(String(rawDefault))
      } : {}
    };
    const isObject = prop.type === "object" && prop.properties;
    const isArrayOfObjects = prop.type === "array" && prop.items?.type === "object" && prop.items.properties;
    return <ParamField {...fieldProps}>
        {prop.description && <p>{renderMd(prop.description)}</p>}

        {prop.enum && <p>
            Allowed values: 
            {prop.enum.map((v, i) => <>{i > 0 && ", "}<code key={i}>{String(v)}</code></>)}
          </p>}

        {constraints.length > 0 && <p className="text-stone-500 dark:text-stone-400 text-sm">
            {constraints.join(" · ")}
          </p>}

        {isComplexDefault && <div className="flex">
            <p>
              <strong>Default:</strong>
            </p>
            <pre className="!my-0">
              <code>
                {JSON.stringify(rawDefault, null, 2)}
              </code>
            </pre>
          </div>}

        {isArrayOfObjects && <Expandable title="item properties">
            <SchemaParamFields schema={{
      properties: prop.items.properties,
      required: prop.items.required
    }} />
          </Expandable>}

        {isObject && <Expandable title="properties">
            <SchemaParamFields schema={{
      properties: prop.properties,
      required: prop.required
    }} />
          </Expandable>}
      </ParamField>;
  };
  return <div>
      {description && <p>{renderMd(description)}</p>}

      {visibleProps.map(renderProp)}
    </div>;
};

export const LwTemplate = ({title = "Key questions to get you started", icon = "sparkles", cta = "Powered by Agent Studio", linkHref = "https://lucidworks.com/demo/?utm_source=docs&utm_medium=referral&utm_campaign=docs_cta_ai"}) => {
  const [isLoaded, setIsLoaded] = useState(false);
  useEffect(() => {
    const timer = setTimeout(() => {
      setIsLoaded(true);
    }, 500);
    return () => clearTimeout(timer);
  }, []);
  return <div className="lw-template-container">
      <Card title={title} icon={icon}>
        {isLoaded && <span dangerouslySetInnerHTML={{
    __html: `<lw-template id="a029c1a9-28be-427e-b0e1-5d918920246a"></lw-template
            >`
  }} />}
        <Link href={linkHref} className="agent-studio-link text-left text-gray-600 gap-2 dark:text-gray-400 text-sm font-medium flex flex-row items-center hover:text-primary dark:hover:text-primary-light group-hover:text-primary group-hover:dark:text-primary-light">Powered by Lucidworks Agent Studio</Link>
      </Card>
    </div>;
};

[localhost link]: http://localhost:3000/docs/5/fusion/reference/config-ref/pipeline-stages/query-stages/recommendation-boosting-query-stage

[mintlify link]: https://doc.lucidworks.com/docs/5/fusion/reference/config-ref/pipeline-stages/query-stages/recommendation-boosting-query-stage

[old doc.lw link]: https://doc.lucidworks.com/fusion/5.9/511

The Boost with Signals query pipeline stage uses [aggregated signals](/docs/5/fusion/getting-data-out/query-enhancement/signals/aggregations) to selectively boost items in the set of search results.

Using the main query and the stage configuration parameters, this stage performs a secondary query to the `COLLECTION_NAME_signals_aggr` collection and returns updated boost weights for the items in the main query’s search results.
Items that have received more user interaction also receive higher boost weights.

See [Recommendation Methods](/docs/5/fusion/getting-data-out/query-enhancement/recommendations/recommendation-methods) for more information.

This stage supports [asynchronous processing](/docs/5/fusion/getting-data-out/query-basics/query-pipelines/overview).

<Tip>
  This stage accesses the `signals_aggr` collection.
  Before using it, verify that the following [permission](/docs/5/fusion/operations/security/access-control/permissions) is set:\
  `GET:/solr/COLLECTION_NAME_signals_aggr/select`
</Tip>

<LwTemplate />

## Signal sources

This stage works with aggregated signals from two sources:

### Fusion native signals

Signals captured via the [Fusion Signals API](/docs/5/fusion/getting-data-in/indexing/indexing-signals/overview) and aggregated by Fusion’s SQL aggregation jobs.

**Collection**: `{APP_NAME}_signals_aggr` (created by Fusion aggregation jobs)

**Aggregation Type values**: Typically `clicks`, `sessions`, or custom aggregation types configured in Fusion

### Platform signals

Pre-aggregated signals from [Lucidworks Platform](/docs/lw-platform/lw-analytics/signals/overview) can be captured via [Signals Beacon](/docs/lw-platform/lw-analytics/signals/signals-beacon) or [Platform Signals API](/docs/lw-platform/lw-analytics/signals/signals-api), then retrieved and indexed by Fusion.

**Collection**: `{APP_NAME}_signals_aggr` (populated by Fusion)

**Aggregation Type values**: Platform formula names such as `formula1`, `formula2`, configured in [Platform signals integration](/docs/5/fusion/getting-data-in/platform-signals/configuration)

**Configuration differences for Platform signals**:

* **Aggregation Type**: Set to the Platform formula name (e.g., `formula1`)
* **Rollup Field**: Use `doc_id` (without `_s` suffix)
* **Rollup Weight Strategy**: Use `weight_d`

See [Platform Signals Integration](/docs/5/fusion/getting-data-in/platform-signals/overview) for setup details.

## Configuration overview

The fields below are especially useful to understand when configuring this stage.

|                                                       |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| ----------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Number of Recommendations**  `numRecommendations`   | Sets the `rows` query param in the main query as the maximum number of query results which will be boosted by this pipeline stage.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| **Number of Signals**  `numSignals`                   | Sets the `rows` query param in the query that searches the `COLLECTION_NAME_signals_aggr` collection, so only the specified number of aggregated signals are retrieved and used for boosting. When signals boosting is applied to a query, aggregated signals records are queried from the appropriate `_signals_aggr` collection to find out the popularity or boost weight for documents which have signals. `numSignals` limits the number of records to be queried from a `_signals_aggr` collection and used to calculate this boost.                                                                                                                                                   |
| **Aggregation Type**  `aggrType`                      | A filter to retrieve aggregated signals in the `COLLECTION_NAME_signals_aggr` collection per each aggregated signal’s `aggr_type_s` field value.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| **Solr Field to Boost On**  `boostId`                 | The document field in the main collection on which to perform boosting. Typically it should use default field, which is `id`.  This field corresponds to the **Rollup Field**/`rollupField` field. Together, these two fields act like a `FIELD:VALUE` pair in the query modification for boosting.                                                                                                                                                                                                                                                                                                                                                                                          |
| **Boost Method**  `boostingMethod`                    | This adds a query parameter to the original query, either “query-param” or “query-parser”. The result is `(“query-param” or “query-parser”) + Boost Param(“boost” or `bq`)`, as in the examples below:  <br /><br />●“query-param”+"boost", result boost query param\*\*:  `boost="map(query({!field f='id' v=‘6239046,13026192}), 0, 0, 1, 27.1705)"`  <br /><br />●“query-parser”+"boost", result boost query param\*\*: `bp_xxx_bbqx="map(query({!field f='id' v=‘6239046,13026192}), 0, 0, 1, 27.1705)"`<br /> <Tip> When `Boost Param` uses `bq`, similar logic applies. When **Boost Param**/`boostingParam` uses “boost”, it works with both “query-param” and “query-parser”. </Tip> |
| **Rollup Field**  `rollupField`                       | Indicates which aggregated signal document field the boost parameter will use for the final boosting. It works in combination with the **Solr Field to Boost On**/`boostId` field.  This should be set to the field in the aggregated signal collection that stores the doc list that is aggregated as one record. By default it’s set to `doc_id_s`.                                                                                                                                                                                                                                                                                                                                        |
| **Rollup Weight Field**  `rollupWeightField`          | Indicates the final boost weight used to calculate the new score for docs retrieved by the main query.  Similar to **Rollup Field**/`rollupField` above, this should be set to the field in the aggregated signal collection that stores the final weight that was calculated. By default it’s `weight_d`.                                                                                                                                                                                                                                                                                                                                                                                   |
| **Final Boost Weight Expression**  `weightExpression` | Calculates the final weight using the weight and score retrieved from the `COLLECTION_NAME_signals_aggr` collection.  The default value is `math:log(weight_d + 1) + 10 * math:log(score+1)`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |

## Solr query parameters

These parameters are used in the **Solr Query parameters**/`queryParams` field for retrieving signal aggregation docs from the `COLLECTION_NAME_signals_aggr` collection. These Solr query params will affect which aggregated signals are used for producing the boosting parameter on the main query.

|                  |                                                                                                                         |
| ---------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `qf=query_t`     | Defines which field to query. In the default case, the query searches on the `query_t` field of aggregated signal docs. |
| `pf=query_t^50`  | Boosts docs within the set of retrieved docs using phrase matching.                                                     |
| `pf2=query_t^20` | `pf2` is similar to `pf`; the difference is that `pf2` works on bigram phrases.                                         |
| `pf3=query_t^10` | `pf3` is similar to `pf`; the difference is that `pf3` works on trigram phrases.                                        |

## FAQs

**If there is `fq` in the main query, how is it matched with the correct aggregated signal?**

In this case, you need to use the `lw.rec.fq` query parameter in the main query. `lw.rec.fq` can be parsed by the Boost with Signals stage, and therefore the filters specified in it can be added to the Solr query that is retrieving the aggregated signals.

For example, if we have filter query param `fq=format:CD&fq=name:Latin`, this needs to be translated into `lw.rec.fq=filters_s:"format:cd $ name:latin"`. Values must be lowercase. The final main query should be:

```sh wrap  theme={"dark"}
http://FUSION_HOST:FUSION_PORT/api/apps/demo_app/query-pipelines/demo_app/collections/demo_app/select?echoParams=all&wt=json&json.nl=arrarr&sort&start=0&q=apple&debug=true&rows=10&lw.rec.fq=filters_s:"format:cd $ name:latin"
```

Now the Boost with Signals stage will only retrieve aggregated signals that have the same filter query.

<Note>
  If there are multiple `fq` values (for example, `format:cd` and `name:latin`), they are ordered alphabetically as strings and joined with " $" (a$ with a space on each side). In the example, `"format:cd $ name:latin"`.
</Note>

**What if my aggregated signals are in a different collection?**

You can point the Boost with Signals stage to a different signal collection by adding a `collection` parameter in the `Solr Query Parameters` section.

<img src="https://mintcdn.com/lucidworks/NR6PWuMFSzL-y-FO/assets/images/4.2/BwS_collection.png?fit=max&auto=format&n=NR6PWuMFSzL-y-FO&q=85&s=2c21676db8d3899144199e3cac8f6f37" alt="BwS collection" width="467" height="656" data-path="assets/images/4.2/BwS_collection.png" />

## Query pipeline stage condition examples

Stages can be triggered conditionally when a script in the **Condition** field evaluates to true.
Some examples are shown below.

Run this stage only for mobile clients:

```js wrap  theme={"dark"}
params.deviceType === "mobile"
```

Run this stage when debugging is enabled:

```js wrap  theme={"dark"}
params.debug === "true"
```

Run this stage when the query includes a specific term:

```js wrap  theme={"dark"}
params.q && params.q.includes("sale")
```

Run this stage when multiple conditions are met:

```js wrap  theme={"dark"}
request.hasParam("fusion-user-name") && request.getFirstParam("fusion-user-name").equals("SuperUser");
!request.hasParam("isFusionPluginQuery")
```

The first condition checks that the request parameter "fusion-user-name" is present and has the value "SuperUser".
The second condition checks that the request parameter "isFusionPluginQuery" is not present.

## Configuration

<Tip>
  When entering configuration values in the UI, use *unescaped* characters, such as `\t` for the tab character. When entering configuration values in the API, use *escaped* characters, such as `\\t` for the tab character.
</Tip>

<SchemaParamFields schema={schema} />
