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

# Reverse Search Index

> Index pipeline stage configuration specifications

export const schema = {
  "type": "object",
  "title": "Reverse Search Index",
  "description": "Indexes saved query documents into a reverse-search collection so they can be matched against content documents during indexing. Specify the target collection, the field containing the query, and optional partition fields to scope matches. Use this stage as part of a reverse-search workflow to flag documents that match pre-registered queries.",
  "required": ["collection", "queryField"],
  "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"]
    },
    "collection": {
      "type": "string",
      "title": "Reverse Search Collection",
      "description": "Specifies the name of the Solr collection where saved query documents are indexed for reverse-search matching. The collection must exist in the Fusion Solr cluster and be configured with a reverse-search schema. An incorrect collection name causes indexing to fail."
    },
    "queryField": {
      "type": "string",
      "title": "Query Field",
      "description": "Specifies the field in the saved query document that contains the Solr query string used for reverse-search matching. This field is read from the incoming document and submitted to the reverse-search index. The field must exist on the document or the stage fails to build the query.",
      "default": "q"
    },
    "commitWithin": {
      "type": "integer",
      "title": "Commit Within",
      "description": "Sets the maximum time in milliseconds Solr waits before committing indexed query documents and making them available for reverse-search lookups. Reduce this value to make newly indexed queries available sooner. Large values improve write throughput at the cost of slower availability.",
      "default": 3000
    },
    "partitionFields": {
      "type": "array",
      "title": "Partition fields",
      "description": "Defines static key-value pairs that are written as partition field values on the indexed query document. Use partition fields to scope reverse-search matches to specific segments such as a tenant ID or product category. Each entry specifies a field name and a static value.",
      "items": {
        "type": "object",
        "required": ["field"],
        "properties": {
          "field": {
            "type": "string",
            "title": "Field",
            "description": "Specifies the name of the partition field to set on the saved query document in the reverse-search collection. Partition fields scope reverse-search lookups to matching segments. The field must exist in the reverse-search collection schema.",
            "hints": ["advanced"]
          },
          "value": {
            "type": "string",
            "title": "Value",
            "description": "Specifies the static value assigned to the partition field on the saved query document. This value is used to filter reverse-search matches to documents with the same partition field value. Use a meaningful tenant or category identifier.",
            "hints": ["advanced"]
          }
        }
      }
    },
    "partitionFieldMapping": {
      "type": "array",
      "title": "Field Mapping",
      "description": "Maps field names from the incoming pipeline document to partition fields on the reverse-search query document. Use this when the partition value comes from the document itself rather than a static value. Each entry specifies a source field on the incoming document and a target partition field on the indexed query document.",
      "hints": ["advanced"],
      "items": {
        "type": "object",
        "required": ["source", "target"],
        "properties": {
          "source": {
            "type": "string",
            "title": "Source Field",
            "description": "Specifies the field name on the incoming pipeline document whose value is read as the partition value. The value is copied to the corresponding target partition field on the indexed query document. The source field must exist on the document or the mapping is skipped.",
            "hints": ["advanced"]
          },
          "target": {
            "type": "string",
            "title": "Partition field",
            "description": "Specifies the partition field name on the reverse-search collection document where the mapped source value is written. The field must exist in the reverse-search collection schema. Use this to dynamically assign partition values from the incoming document.",
            "hints": ["advanced"]
          }
        }
      }
    }
  },
  "category": "Advanced",
  "categoryPriority": 3,
  "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/lucidworks-search/09-developer-documentation/config-specs/index-pipeline-stages/reverse-search-index

[mintlify link]: https://doc.lucidworks.com/docs/lucidworks-search/09-developer-documentation/config-specs/index-pipeline-stages/reverse-search-index

[old doc.lw link]: https://doc.lucidworks.com/managed-fusion/5.9/qwfh7n

The Reverse Search index stage is used for Reverse Search. See [Reverse Search](/docs/lucidworks-search/04-move-data-in/index-pipeline/reverse-search) for more information.

<LwTemplate />

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