> ## 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.

# Field Facet Stage

export const schema = {
  "type": "object",
  "title": "Facets",
  "description": "Adds range or field facets to the Solr query, enabling aggregation and categorization of results by field values.",
  "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"]
    },
    "fieldFacets": {
      "type": "array",
      "title": "Facet Fields",
      "items": {
        "type": "object",
        "required": ["field"],
        "properties": {
          "field": {
            "type": "string",
            "title": "Field",
            "description": "Specifies the field name(s) for field operations in the document processing pipeline."
          },
          "prefix": {
            "type": "string",
            "title": "Prefix",
            "description": "String prepended to field names or values to create namespaces, avoid collisions, or organize related fields hierarchically. For field name prefixing, transforms `title` to `product_title` when prefix is `product_`. For value prefixing, prepends the string to each value."
          },
          "sort": {
            "type": "string",
            "title": "Sort",
            "description": "Ordering of the faceting results.",
            "enum": ["count", "index"]
          },
          "limit": {
            "type": "integer",
            "title": "Limit",
            "description": "Maximum number of facets to return."
          },
          "offset": {
            "type": "integer",
            "title": "Offset",
            "description": "Offset into list of resulting facets."
          },
          "minCount": {
            "type": "integer",
            "title": "Minimum Count",
            "description": "Lower threshold of term counts to be included.",
            "default": 1
          },
          "missing": {
            "type": "boolean",
            "title": "Count Missing",
            "description": "Optionally include a 'missing' facet bucket for documents without the selected field.",
            "default": false
          },
          "method": {
            "type": "string",
            "title": "Method",
            "enum": ["per_term", "per_doc", "per_segment", "doc_values", "un_inverted_field", "doc_values_hash", "enum"]
          },
          "enumCacheMinDf": {
            "type": "integer",
            "title": "Enum Cache Minimum DF",
            "description": "This property is only supported for non DSL requests."
          },
          "ensuredValues": {
            "type": "array",
            "title": "Ensured Facet Values",
            "description": "Field values to include statistics for, even if they don't fall within the natural top-\"limit\"values for the facet.  Only supported on DSL requests.",
            "items": {
              "type": "string"
            }
          },
          "boostValues": {
            "type": "array",
            "title": "Boost Values",
            "description": "Field values to boost in the facet results. (Requires Modify Response stage)",
            "items": {
              "type": "string"
            }
          },
          "buryValues": {
            "type": "array",
            "title": "Bury Values",
            "description": "Field values to bury in the facet results. (Requires Modify Response stage)",
            "items": {
              "type": "string"
            }
          },
          "suppressValues": {
            "type": "array",
            "title": "Suppress Values",
            "description": "Field values to suppress from the facet results. (Requires Modify Response stage)",
            "items": {
              "type": "string"
            }
          },
          "threads": {
            "type": "integer",
            "title": "NO LONGER USED.",
            "hints": ["hidden"],
            "minimum": 0,
            "exclusiveMinimum": false
          },
          "order": {
            "type": "integer",
            "title": "Display Order",
            "description": "Order in which this facet appears in the response. Lower values appear first. If not specified, facet appears after all ordered facets.",
            "minimum": 0,
            "exclusiveMinimum": false
          }
        }
      }
    },
    "threads": {
      "type": "integer",
      "title": "Field facet threads (Advanced)",
      "description": "Sets the number of threads Solr uses when loading fields for faceting. Keep at `0` or unset to use the query thread. Applies only to non-DSL requests."
    },
    "rangeFacets": {
      "type": "array",
      "title": "Range Facet Fields",
      "items": {
        "type": "object",
        "required": ["field", "start", "end", "gap"],
        "properties": {
          "field": {
            "type": "string",
            "title": "Field",
            "description": "Specifies the field name(s) for field operations in the document processing pipeline."
          },
          "start": {
            "type": "string",
            "title": "Start",
            "description": "Specifies the lower bound of the range."
          },
          "end": {
            "type": "string",
            "title": "End",
            "description": "Specifies the upper bound of the range."
          },
          "gap": {
            "type": "string",
            "title": "Gap",
            "description": "The span of each range expressed as a value to be added to the lower bound."
          },
          "hardEnd": {
            "type": "boolean",
            "title": "Hard End",
            "description": "Specifies how to handle cases where the gap does not divide evenly between start and end."
          },
          "minCount": {
            "type": "integer",
            "title": "Minimum Count",
            "description": "Lower threshold of term counts to be included.",
            "default": 1
          },
          "method": {
            "type": "string",
            "title": "Method",
            "enum": ["filter", "doc_values"]
          },
          "include": {
            "type": "array",
            "title": "Include",
            "description": "Specifies how bounds are processed.",
            "items": {
              "type": "string",
              "enum": ["lower", "upper", "outer", "edge", "all"]
            }
          },
          "other": {
            "type": "array",
            "title": "Other",
            "description": "Specifies additional counts.",
            "items": {
              "type": "string",
              "enum": ["before", "after", "between", "non", "all"]
            }
          },
          "boostValues": {
            "type": "array",
            "title": "Boost Values",
            "description": "Field values to boost in the facet results.",
            "items": {
              "type": "string"
            }
          },
          "buryValues": {
            "type": "array",
            "title": "Bury Values",
            "description": "Field values to bury in the facet results.",
            "items": {
              "type": "string"
            }
          },
          "suppressValues": {
            "type": "array",
            "title": "Suppress Values",
            "description": "Field values to suppress from the facet results.",
            "items": {
              "type": "string"
            }
          },
          "order": {
            "type": "integer",
            "title": "Display Order",
            "description": "Order in which this facet appears in the response. Lower values appear first. If not specified, facet appears after all ordered facets.",
            "minimum": 0,
            "exclusiveMinimum": false
          }
        }
      }
    }
  },
  "category": "Set Up",
  "categoryPriority": 8,
  "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/facet-query-stage

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

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

The Field Facet query pipeline stage is used to add a
link:[Solr Field Facet query](https://cwiki.apache.org/confluence/display/solr/Faceting#Faceting-Field-ValueFacetingParameters)
to the search query pipeline.

A field facet query computes the top values for a field and returns the list of those values along with a count of the subset
of documents in the search results which match that term.
Field faceting works best over fields which contain a single label or set of labels from a finite, controlled lexicon
such as product category.
Facet field parameters can be tuned for performance, see:
[Facet Field Configuration](https://cwiki.apache.org/confluence/display/solr/Faceting#Faceting-Field-ValueFacetingParameters).

It is possible to specify more than one field facets.
For each field facet you must specify the field name plus the following additional parameters:

* **Limit.** The maximum number of terms to be returned. Default 100.
* **Offset.** The number of top facet values to skip in the response. Default 0.
* **Sort.** The order in which to list facet values: `count` ordering is by documents per term, descending, and `index` ordering is sorted on term values themselves.
* **Missing.** The number of documents in the results set which have no value for the facet field.
* **Choice of facet method (advanced).** Specify Solr algorithm used to calculate facet counts.
  (See [Facet Method Configuration](https://cwiki.apache.org/confluence/display/solr/Faceting#Faceting-Thefacet.methodParameter) for details)\
  One of:

  * `enum`. Small number of distinct categories.
  * `fc` ("field cache"). Many different values in the field, each document has low number of values, multi-valued field.
  * `fcs` ("single value string fields"). Good for rapidly changing indexes.

For further details see: [Solr Faceting Overview](https://lucene.apache.org/solr/guide/faceting.html).

<Card title="Faceting" class="note-image" href="https://academy.lucidworks.com/faceting-course" cta="Take this course on the LucidAcademy." icon="graduation-cap" iconType="duotone">
  The course for **Faceting** focuses on how to use facets to ensure faster, smarter search results.
</Card>

<LwTemplate />

## 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

<SchemaParamFields schema={schema} />
