Make text searchable
The language tabs use earlier client interfaces. Check SDK versions and connection setup before running them.
Add a document’s words to a full-text index. Keep its ID aligned with the source row so the application can open each match.
Before you run it: Updating a source row does not update this index automatically; submit changed text again.
A full-text index is a lookup from words to document IDs. The sample writes one document, p001, under shop.products/description. After the write, use single-word search for wireless; with only this sample loaded, expect p001. A source row is optional for this index operation but needed if your application later fetches product details.
- Choose p001 and a fieldKeep the table and field names identical across requests.
- Index its textWait for the successful indexing response.
- Search for wirelessLook for p001 in the matching IDs.
- Read the source if storedUse its ID to fetch the original row separately.
Follow the example
- Choose the table, field and document ID.
- Send the text.
- Check the write response.
- Search for a word just indexed.
Run the request
FTS is a runtime endpoint - there is no [[extractions.fts]] block on the schema and no setup step. The first POST creates the index.
curl -X POST "https://$OC_HOST/v1/tenants/$OC_TENANT/fts/shop.products/description" \
-H "Authorization: Bearer $OC_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"doc_id": "p001",
"text": "Wireless over-ear headphones with active noise cancellation and 30-hour battery life."
}'Check the result
The write returns 201 with an empty body. Reusing an ID replaces that document’s indexed text.
HTTP/1.1 201 Created
(empty body)A successful index returns 201 Created with no response body. There is no tokens_indexed count or confirmation JSON - check the status code, not the body.
Understand the behavior
- The text is tokenised, lowercased, and the per-token postings are written to the inverted index keyed by
(schema, field, token). - If a doc with this
doc_idalready exists in this field's index, the previous postings are removed and the new ones written in a single atomic batch. There is no window where both versions are visible. - Each field is an independent index. Indexing
descriptiondoes nothing totitle. :tableand:fieldare opaque path segments - they are not validated against any schema. They must match exactly (byte-for-byte) between the index POST and the search GET. Index undershop.productsand queryshop_productsand you get a silent empty result, not an error.
Important limits and checks
- Forgetting to re-index on writes. Updating the source row's text in
/rowsdoes not update the FTS index. You have to POST to the FTS endpoint again, or wire a hook that does it for you. - Using something other than the primary key for
doc_id. Search returnsdoc_ids - if it's not the row's PK you'll need an extra lookup on every hit. - Indexing multi-MB blobs as a single doc. Very large documents bloat the postings and hurt scoring. Split into chunks (e.g. one doc_id per paragraph or per page) and let the search side merge.