Vector Search Schema Reference
Every Opensolr index is a real Apache Solr core with its own schema.xml, and that file is yours: you can edit it or replace it with any schema Solr accepts. This page documents one specific schema: the generic vector search schema that Opensolr ships on vector-enabled indexes, and that all Opensolr data tools write into.
It is the schema behind the Web Crawler, the Data Ingestion API, the Drupal module, the WordPress plugin, the LangChain, LlamaIndex, Haystack, Laravel Scout and MCP packages, and the hosted search page. If you use any of those, this is your schema, and the page explains every field, every type suffix and every analyser in it. If you brought your own configset, your schema is whatever you made it, and this page is a reference for what the Opensolr tools expect.
Open your index in the control panel and go to Configuration: the schema.xml you see there is the live file for that index, and you can change it or upload a whole configset of your own. Indexes created with a custom configset, or before the vector schema existed, will look different from this page. Keep in mind that the crawler, the modules, the packages and the hosted search page read the fields described here by name; a custom schema that drops them loses those tools.
How to read a Solr schema
A schema has three kinds of entries. A field is a named column with a type. A dynamicField is a name pattern such as *_f: any field whose name matches the pattern is created on the fly with that type. A fieldType defines how values are stored and, for text, how they are broken into searchable terms.
Each field carries a few switches. They decide what you can do with it:
indexedog_image is the only content field with indexed=false: it is returned in results but you cannot search it.storedspell, the autocomplete fields, embeddings) are stored=false to save disk.docValuesmultiValuedm (_sm, _fm, _im, _dtm) are multi-valued; their single-letter siblings hold exactly one value.termVectorsuri, title, description, text and every *_t field. Costs roughly 30 to 50 percent extra index size on those fields.Relevance uses BM25, Solr's default under SchemaSimilarityFactory. Field weights on top of it are set in Search Tuning.
What you send, and what the pipeline adds
A document enters through the crawler or the ingestion API with four required fields: uri, title, description, text. Everything else is optional. Before the document reaches Solr, the pipeline derives the fields below. You never have to send them, and if you do, your value wins where the table says so.
| Field | Derived from | Your value |
|---|---|---|
id | MD5 of the normalised uri (trailing slash removed). Re-sending the same uri updates the document instead of duplicating it. | Ignored |
uri_s, title_s, author_s | Exact-string copies of uri, title, author, for faceting and exact filtering. | Overwritten |
tags, title_tags | Cleaned words from title, description and the first 3,000 characters of text, feeding the autocomplete fields. | Overwritten |
spell | Same word list as tags, used to build the "did you mean" dictionary. | Overwritten |
embeddings | A 1,024-dimension vector of title + description + the first complete sentences of the text (or text_t when present). Skipped on plans without vector search. | Ignored |
sent_pos, sent_neu, sent_neg, sent_com | Sentiment scores of the same text. | Overwritten |
meta_detected_language | Language detected from title + description. | Kept if you send one |
creation_date, meta_creation_date | Derived from timestamp when you send it (unix epoch or any parseable date). | Kept |
size | Bytes of title + description + text. | Overwritten |
meta_domain | Host of the uri, without www. | Kept if you send one |
content_type | Defaults to text/html; for rtf:true documents the real MIME type of the fetched file. | Kept |
category, og_image, meta_icon, meta_og_locale | Set to an empty string when missing, so the search page never hits an absent field. | Kept |
Any other key in your document is passed to Solr unchanged. That is the whole trick of the type suffixes below: the pipeline does not map or rename anything, the schema pattern does.
Core fields
These fields exist on every document. Types refer to the field types explained further down.
Content
| Field | Type | Role |
|---|---|---|
id | string | Unique key. MD5 of the URI. |
uri | text_general | The document URL, searchable word by word. Highlighting enabled. |
title | text_general | Highest default search weight. Highlighting enabled. |
description | text_general | Second search weight, used for result snippets. Highlighting enabled. |
text | text_general | The full body. Largest field, lowest default weight. Highlighting enabled. |
author | text_general | Searchable author name. Exact copy in author_s. |
Metadata, time and numbers
| Field | Type | Role |
|---|---|---|
content_type | string | MIME type (text/html, application/pdf, image/png). Facet and filter. |
content_status | string | HTTP status recorded by the crawler. |
signature | string | Content hash used for de-duplication. |
category | string | Free category label. Facet and filter. |
og_image | string | Thumbnail URL. Stored, not searchable. |
creation_date | pdate | Publish date. Range filters and freshness sorting. |
timestamp | plong | Unix epoch of the same moment. Fast numeric sorting. |
rank | pint | Custom ranking value, default 0. Available to boost functions. |
size | pint | Content size in bytes. |
Geo and sentiment
| Field | Type | Role |
|---|---|---|
coords | location | Latitude,longitude point for distance filters and sorting ({!geofilt}, geodist()). |
lat, lon | pdouble | The same coordinates as plain numbers, default 0.0. |
sent_pos, sent_neu, sent_neg | pdouble | Positive, neutral and negative sentiment, 0 to 1. |
sent_com | pdouble | Compound sentiment, -1 to 1. Filter with sent_com:[0.5 TO *] for clearly positive content. |
Search-only fields (indexed, never returned)
| Field | Type | Role |
|---|---|---|
spell | textSpell | Dictionary for "did you mean" suggestions, wired to the spellcheck component in search.xml. |
tags, title_tags | edgy_text_kw | Prefix matching on the whole phrase. title_tags is the default autocomplete field. |
tags_ws, title_tags_ws | edgy_text_ws | Prefix matching on each word separately. |
embeddings | knn_vector | The 1,024-dimension vector behind semantic and hybrid search. Not stored: it cannot be read back, only searched. |
_version_, _root_ | plong, string | Solr internals for optimistic concurrency and nested documents. Leave them alone. |
Dynamic fields: add any field with a suffix
You do not edit the schema to add a field. You name it with the right suffix and Solr creates it with the matching type the first time it sees it. The suffix decides everything: whether the value is searched as text or matched exactly, whether you can facet, sort and filter by range, and which widget the facet sidebar uses for it.
| Suffix | Solr type | Example | Facet | Sort | Range | Full-text |
|---|---|---|---|---|---|---|
*_s | string | currency_s: "EUR" | List | yes | no | exact |
*_sm | string, multi | brand_sm: ["Nike","Asics"] | List | no | no | exact |
*_ss | string, multi | colour_ss: ["red","blue"] | List | no | no | exact |
*_t | text_general | specs_t: "Gore-Tex upper" | no | no | no | yes |
*_i | pint | stock_i: 42 | Slider | yes | yes | no |
*_im | pint, multi | sizes_im: [40,41,42] | Slider | no | yes | no |
*_l | plong | views_l: 1284930112 | Slider | yes | yes | no |
*_f | pfloat | price_f: 79.99 | Slider | yes | yes | no |
*_fm | pfloat, multi | prices_fm: [79.99,69.99] | Slider | no | yes | no |
*_d | pdouble, multi | weight_d: [0.245] | Slider | no | yes | no |
*_dt | pdate | date_dt: "2026-01-15T10:30:00Z" | Date range | yes | yes | no |
*_dtm | pdate, multi | events_dtm: [...] | Date range | no | yes | no |
*_b | boolean | in_stock_b: true | List | yes | no | no |
meta_* | string | meta_sku: "AX-100" | List | yes | no | exact |
phonetic_* | text_general_ phonetic | phonetic_title | no | no | no | sounds-like |
ignored_**_nlp | ignored, multi | ignored_debug | no | no | no | no |
Rules worth knowing
2026-01-15T10:30:00Z. A bare 2026-01-15 or a unix epoch is rejected on a _dt field. Send the epoch in timestamp instead and the pipeline fills creation_date for you.meta_price_f matches meta_* (6 characters) before *_f (3), so it becomes a string and loses range filters. Keep type suffixes out of the meta_ namespace: use price_f.price, is rejected by Solr and the document fails. There is no catch-all. Every custom field needs a suffix or the meta_ prefix.brand_s: ["a","b"]) fails. Sending a single value to a multi-valued field is fine._sm, _fm, _im, _dtm, _d are for faceting and filtering, not sort=._s or meta_ field matches the whole value, case-sensitively. If people should be able to search the text, send it in a _t field too, or fold it into text.price_f has been indexed as a float you cannot later send "n/a" into it.A product, start to finish
One JSON document through the ingestion API, and the queries the suffixes make possible.
{
"uri": "https://shop.example.com/products/trail-runner-x",
"title": "Trail Runner X",
"description": "Lightweight trail shoe with a Gore-Tex upper.",
"text": "Full product description, care instructions, reviews ...",
"timestamp": 1768473000,
"price_f": 129.0,
"currency_s": "EUR",
"brand_sm": ["Asics"],
"sizes_im": [40, 41, 42, 43],
"in_stock_b": true,
"specs_t": "Gore-Tex upper, Vibram sole, 245 g",
"meta_sku": "TRX-129"
}What that buys you on the query side, with plain Solr parameters:
| You want | Parameter |
|---|---|
| Shoes between 100 and 150 euro | fq=price_f:[100 TO 150]&fq=currency_s:EUR |
| Only in stock, cheapest first | fq=in_stock_b:true&sort=price_f asc |
| Brand counts for the sidebar | facet=true&facet.field=brand_sm |
| Anything with size 42 | fq=sizes_im:42 |
| Added in the last 30 days | fq=creation_date:[NOW-30DAYS TO NOW] |
| Average price per brand | json.facet={brands:{type:terms,field:brand_sm,facet:{avg:"avg(price_f)"}}} |
| Look up by your own SKU | fq=meta_sku:TRX-129 |
The hosted search page builds these for you from the Facet Filters configuration. Direct Solr access works with the connection details on your dashboard.
Field types and how text is analysed
A text field is never matched against the raw value. At index time the value is turned into a stream of normalised terms; at query time your words go through a near-identical chain, and the two streams are compared. That is why running finds run, café finds cafe, and a synonym you add in synonyms.txt works without reindexing.
text_general: the main search type
Used by uri, title, description, text, author and every *_t field. The index-time chain, in order:
- 01
HTMLStripCharFilterRemoves any HTML tags left in the value. - 02
MappingCharFilterAppliesmapping-ISOLatin1Accent.txt: é → e, ß → ss, before tokenising. - 03
ICUTokenizerSplits text into words using Unicode rules, so Chinese, Japanese, Thai and mixed-script text tokenise correctly. - 04
CJKWidthFilterNormalises full-width and half-width CJK characters. - 05
EnglishPossessiveFilterOpensolr's becomes Opensolr. - 06
ASCIIFoldingFilterSecond accent pass for anything the mapping file missed. - 07
StopFilterDrops the words listed instopwords.txt(the, and, ...). - 08
WordDelimiterGraphFilterWi-Fi becomes wi, fi and wifi; iPhone15 becomes iphone, 15, iphone15. The original token is kept too. Words inprotwords.txtare left untouched. - 09
LowerCaseFilterEverything lower-case. - 10
SnowballPorterFilterEnglish stemming: running, runs, runner share the stem run.protwords.txtexempts words from stemming. - 11
LengthFilterDrops tokens longer than 500 characters (base64 blobs, broken markup). - 12
RemoveDuplicatesTokenFilterCollapses tokens that ended up identical at the same position.
The query-time chain is the same with one addition: SynonymGraphFilter expands your words with synonyms.txt at query time only. Adding a synonym therefore takes effect on the next search, after a core reload, with no reindex. Both chains use the same stopword, protected-word and accent files, all editable under Configuration.
edgy_text_kw and edgy_text_ws: autocomplete
Edge n-gram types. At index time every term is expanded into its prefixes, 1 to 25 characters long: runner becomes r, ru, run, runn, runne, runner. At query time there is no n-gram step, so what you type is matched as an exact prefix. The difference between the two:
edgy_text_kwKeywordTokenizer: the whole value is one token, then split by WordDelimiterGraphFilter. Non-alphanumerics are stripped. Best for matching the start of a full title. Fields: tags, title_tags.edgy_text_wsWhitespaceTokenizer: each word is its own token, so typing run matches Trail Runner on the second word. Fields: tags_ws, title_tags_ws.These four fields also sit in the default search with a tiny weight (0.1), which is what makes partial words rank at all. See Search Tuning.
textSpell: the spellcheck dictionary
Deliberately minimal: StandardTokenizer and lower-casing, nothing else. No stemming, no stopwords, so the dictionary contains real words as they appear in your content. The spellcheck component in search.xml reads the spell field, allows up to 2 edits between the typed word and a suggestion, and only tries to correct words that occur in fewer than half of all documents: a word that common is assumed to be spelled right.
text_general_phonetic: sounds-like matching
Available for any phonetic_* field. After stemming, PhoneticFilter with the Double Metaphone encoder adds a phonetic code next to each term, so Smyth matches Smith and Kathryn matches Catherine. The crawler fills phonetic_title, phonetic_description and phonetic_text; the ingestion API leaves them empty. It roughly doubles the size of those fields, which is why it is opt-in.
knn_vector: the embedding
solr.DenseVectorField with vectorDimension="1024" and cosine similarity. The dimension is fixed by the embedding model Opensolr runs; a vector of any other length is rejected. Searched with {!knn f=embeddings topK=N} or, on Opensolr, through the {!hybrid} parser that fuses it with keyword scores. Details of the model and the API in AI & Vector Search.
Primitive and special types
| Type | Solr class | Notes |
|---|---|---|
string | StrField | Exact value, case-sensitive, docValues on. Missing values sort last. |
boolean | BoolField | true / false. Also accepts 1, t, T as true. |
pint, plong, pfloat, pdouble | *PointField | Point-based numerics, fast range queries. The legacy names int, tint, float, tfloat and so on map to the same classes for compatibility with old configs. |
pdate | DatePointField | ISO 8601 UTC. Supports date math: [NOW-7DAYS TO NOW], NOW/DAY. |
location | LatLonPointSpatialField | "lat,lon" strings. {!geofilt sfield=coords pt=44.43,26.10 d=25} filters within 25 km. |
ignored | StrField, indexed=false, stored=false | Accepted and thrown away. Lets you send documents with extra keys without failing. |
What is not in schema.xml
<copyField> to fill title_s from title; here the pipeline writes those copies itself. If you index through Solr's /update handler directly, bypassing the crawler and the ingestion API, you must send uri_s, title_s, tags, title_tags and spell, or those features stay empty for your documents./select, the spellcheck component and /autocomplete live in search.xml, included from solrconfig.xml. Default search field is text.qf weights from Search Tuning at query time.{!hybrid} is a Solr plugin installed on Opensolr clusters, registered in solrconfig.xml, not a schema entry.Changing the schema
The file is yours. Edit it under Configuration, save, and reload the core from Index Tools. A few things to keep in mind before you do:
- Adding a field, a dynamic pattern or a field type is safe and takes effect on reload.
- Changing the type of a field that already holds data requires a reindex: existing documents were analysed with the old type and will not match the new one.
- Do not rename or remove the core fields. The crawler, the ingestion pipeline, the search page and the AI features read them by name.
vectorDimensionmust stay 1024 while you use Opensolr embeddings. Change it only if you index your own vectors from a different model.- Word lists (
synonyms.txt,stopwords.txt,protwords.txt) change behaviour on reload. Synonyms apply at query time and need no reindex; stopwords and protected words affect index-time analysis, so a reindex makes them apply to old documents too. - If you moved to a
managed-schemainstead, the same fields and types apply; the file format differs. See managed-schema to schema.xml.
The file itself
This is the exact generic vector search schema.xml that Opensolr deploys on vector-enabled indexes, compatible with Solr 9.x. Everything explained above is in here. Scroll through it, or copy it as the starting point for a schema of your own.
449 lines, last updated 2 September 2026.
<?xml version="1.0" encoding="UTF-8"?> <schema name="opensolr-crawler-solr9.x-optimized" version="2.1"> <similarity class="solr.SchemaSimilarityFactory"/> <!-- ============================================================================ OPENSOLR OPTIMIZED SCHEMA ============================================================================ DOCVALUES EXPLAINED: - docValues=true stores column-oriented data for fast sorting, faceting, grouping - Use for: fields you sort on, facet on, or use in function queries - Don't use for: large text fields (wastes disk space) - String/numeric fields: almost always benefit from docValues - Text fields: cannot use docValues (use for full-text search only) TERMVECTORS EXPLAINED: - termVectors=true enables highlighting, more-like-this, term statistics - termPositions=true needed for phrase highlighting - termOffsets=true needed for fast highlighting - storeOffsetsWithPositions=true enables even faster highlighting - Use for: fields you want to highlight or use for MLT - Cost: increases index size ~30-50% ============================================================================ --> <!-- ============================================================================ UNIQUE KEY - Required ============================================================================ --> <field name="id" type="string" indexed="true" stored="true" required="true" docValues="true"/> <uniqueKey>id</uniqueKey> <!-- ============================================================================ CORE CONTENT FIELDS - These are your main searchable fields ============================================================================ --> <!-- URI: searchable URL, also used for deduplication --> <field name="uri" type="text_general" indexed="true" stored="true" termVectors="true" termPositions="true" termOffsets="true" storeOffsetsWithPositions="true"/> <!-- Title: most important search field, heavily weighted --> <field name="title" type="text_general" indexed="true" stored="true" termVectors="true" termPositions="true" termOffsets="true" storeOffsetsWithPositions="true"/> <!-- Description: second most important, used for snippets --> <field name="description" type="text_general" indexed="true" stored="true" termVectors="true" termPositions="true" termOffsets="true" storeOffsetsWithPositions="true"/> <!-- Text: main body content, lowest weight but largest field --> <field name="text" type="text_general" indexed="true" stored="true" termVectors="true" termPositions="true" termOffsets="true" storeOffsetsWithPositions="true"/> <!-- Author: searchable, may want to facet on this --> <field name="author" type="text_general" indexed="true" stored="true"/> <!-- ============================================================================ METADATA FIELDS - For filtering, faceting, sorting docValues=true on these for fast faceting/sorting ============================================================================ --> <!-- Content type: filter by type (text/html, image/png, etc) --> <field name="content_type" type="string" indexed="true" stored="true" docValues="true"/> <!-- Content status: HTTP status codes, crawl status --> <field name="content_status" type="string" indexed="true" stored="true" docValues="true"/> <!-- Signature: content hash for deduplication --> <field name="signature" type="string" indexed="true" stored="true" docValues="true"/> <!-- Category: for categorization/faceting --> <field name="category" type="string" indexed="true" stored="true" docValues="true"/> <!-- OG Image: stored only, not searchable --> <field name="og_image" type="string" indexed="false" stored="true"/> <!-- ============================================================================ DATE/TIME FIELDS - For freshness sorting and filtering docValues=true essential for date range queries and sorting ============================================================================ --> <!-- Creation date: when content was published/created --> <field name="creation_date" type="pdate" indexed="true" stored="true" docValues="true"/> <!-- Timestamp: unix timestamp, useful for sorting --> <field name="timestamp" type="plong" indexed="true" stored="true" docValues="true"/> <!-- ============================================================================ NUMERIC FIELDS - For scoring, filtering, sorting docValues=true for fast range queries and sorting ============================================================================ --> <!-- Rank: page rank or custom scoring --> <field name="rank" type="pint" indexed="true" stored="true" docValues="true"/> <!-- Size: document size in bytes --> <field name="size" type="pint" indexed="true" stored="true" docValues="true" default="0"/> <!-- ============================================================================ GEOSPATIAL FIELDS - For location-based search ============================================================================ --> <field name="coords" type="location" indexed="true" stored="true"/> <field name="lat" type="pdouble" indexed="true" stored="true" docValues="true" default="0.0"/> <field name="lon" type="pdouble" indexed="true" stored="true" docValues="true" default="0.0"/> <!-- ============================================================================ SENTIMENT FIELDS - For sentiment analysis filtering docValues=true for range queries (e.g., "show positive articles") ============================================================================ --> <field name="sent_pos" type="pdouble" indexed="true" stored="true" docValues="true" default="0"/> <field name="sent_neu" type="pdouble" indexed="true" stored="true" docValues="true" default="0"/> <field name="sent_neg" type="pdouble" indexed="true" stored="true" docValues="true" default="0"/> <field name="sent_com" type="pdouble" indexed="true" stored="true" docValues="true" default="0"/> <!-- ============================================================================ SPELLCHECK FIELD - For "did you mean" suggestions Not stored, only indexed for spellcheck component ============================================================================ --> <field name="spell" type="textSpell" indexed="true" stored="false" multiValued="true"/> <!-- ============================================================================ AUTOCOMPLETE / EDGE NGRAM FIELDS - For typeahead suggestions These create prefix-matching indexes ============================================================================ --> <field name="tags" type="edgy_text_kw" indexed="true" stored="false"/> <field name="title_tags" type="edgy_text_kw" indexed="true" stored="false"/> <field name="tags_ws" type="edgy_text_ws" indexed="true" stored="false"/> <field name="title_tags_ws" type="edgy_text_ws" indexed="true" stored="false"/> <!-- ============================================================================ VECTOR EMBEDDINGS - For semantic/AI search stored=false saves space (embeddings are large), only need for search ============================================================================ --> <field name="embeddings" type="knn_vector" indexed="true" stored="false"/> <!-- ============================================================================ DYNAMIC FIELDS - Flexible metadata without schema changes ============================================================================ --> <!-- Generic meta fields: string type with docValues for faceting --> <dynamicField name="meta_*" type="string" indexed="true" stored="true" docValues="true"/> <!-- Brighteon-specific: text type for full-text search --> <dynamicField name="meta_brighteon_*" type="text_general" indexed="true" stored="true"/> <!-- Numeric dynamic fields --> <dynamicField name="*_d" type="pdouble" indexed="true" stored="true" docValues="true" multiValued="true"/> <dynamicField name="*_i" type="pint" indexed="true" stored="true" docValues="true"/> <dynamicField name="*_l" type="plong" indexed="true" stored="true" docValues="true"/> <dynamicField name="*_f" type="pfloat" indexed="true" stored="true" docValues="true"/> <!-- String dynamic fields with docValues --> <dynamicField name="*_sm" type="string" indexed="true" stored="true" docValues="true" multiValued="true"/> <dynamicField name="*_s" type="string" indexed="true" stored="true" docValues="true"/> <dynamicField name="*_ss" type="string" indexed="true" stored="true" docValues="true" multiValued="true"/> <!-- Text dynamic fields for full-text search --> <dynamicField name="*_t" type="text_general" indexed="true" stored="true" termVectors="true" termPositions="true" termOffsets="true"/> <!-- Date dynamic fields --> <dynamicField name="*_dt" type="pdate" indexed="true" stored="true" docValues="true"/> <dynamicField name="*_im" type="pint" indexed="true" stored="true" docValues="true" multiValued="true"/> <dynamicField name="*_fm" type="pfloat" indexed="true" stored="true" docValues="true" multiValued="true"/> <dynamicField name="*_dtm" type="pdate" indexed="true" stored="true" docValues="true" multiValued="true"/> <!-- Boolean dynamic fields --> <dynamicField name="*_b" type="boolean" indexed="true" stored="true" docValues="true"/> <!-- Phonetic search fields --> <dynamicField name="phonetic_*" type="text_general_phonetic" indexed="true" stored="false"/> <!-- Ignored fields - not indexed or stored --> <dynamicField name="ignored_*" type="ignored" multiValued="true"/> <dynamicField name="*_nlp" type="ignored" multiValued="true"/> <!-- ============================================================================ INTERNAL SOLR FIELDS - Required by Solr, don't modify ============================================================================ --> <field name="_version_" type="plong" indexed="false" stored="false" docValues="true"/> <field name="_root_" type="string" indexed="true" stored="false" docValues="true"/> <!-- ============================================================================ ============================================================================ FIELD TYPES ============================================================================ ============================================================================ --> <fieldType name="text_general" class="solr.TextField" positionIncrementGap="100"> <analyzer type="index"> <charFilter class="solr.HTMLStripCharFilterFactory"/> <charFilter class="solr.MappingCharFilterFactory" mapping="mapping-ISOLatin1Accent.txt"/> <tokenizer class="solr.ICUTokenizerFactory"/> <filter class="solr.CJKWidthFilterFactory"/> <filter class="solr.EnglishPossessiveFilterFactory"/> <filter class="solr.ASCIIFoldingFilterFactory" preserveOriginal="false"/> <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt"/> <filter class="solr.WordDelimiterGraphFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="1" catenateNumbers="1" catenateAll="1" splitOnCaseChange="1" splitOnNumerics="1" preserveOriginal="1" protected="protwords.txt"/> <filter class="solr.FlattenGraphFilterFactory"/> <filter class="solr.LowerCaseFilterFactory"/> <filter class="solr.SnowballPorterFilterFactory" language="English" protected="protwords.txt"/> <filter class="solr.LengthFilterFactory" min="1" max="500"/> <filter class="solr.RemoveDuplicatesTokenFilterFactory"/> </analyzer> <analyzer type="query"> <charFilter class="solr.HTMLStripCharFilterFactory"/> <charFilter class="solr.MappingCharFilterFactory" mapping="mapping-ISOLatin1Accent.txt"/> <tokenizer class="solr.ICUTokenizerFactory"/> <filter class="solr.CJKWidthFilterFactory"/> <filter class="solr.EnglishPossessiveFilterFactory"/> <filter class="solr.ASCIIFoldingFilterFactory" preserveOriginal="false"/> <filter class="solr.SynonymGraphFilterFactory" ignoreCase="true" synonyms="synonyms.txt" expand="true"/> <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt"/> <filter class="solr.WordDelimiterGraphFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="1" catenateNumbers="1" catenateAll="1" splitOnCaseChange="1" splitOnNumerics="1" preserveOriginal="1" protected="protwords.txt"/> <filter class="solr.LowerCaseFilterFactory"/> <filter class="solr.SnowballPorterFilterFactory" language="English" protected="protwords.txt"/> <filter class="solr.LengthFilterFactory" min="1" max="500"/> <filter class="solr.RemoveDuplicatesTokenFilterFactory"/> </analyzer> </fieldType> <!-- ============================================================================ TEXTSPELL - For spellcheck dictionary building Minimal analysis: just tokenize and lowercase ============================================================================ --> <fieldType name="textSpell" class="solr.TextField" positionIncrementGap="100"> <analyzer type="index"> <tokenizer class="solr.StandardTokenizerFactory"/> <filter class="solr.LowerCaseFilterFactory"/> </analyzer> <analyzer type="query"> <tokenizer class="solr.StandardTokenizerFactory"/> <filter class="solr.LowerCaseFilterFactory"/> </analyzer> </fieldType> <!-- ============================================================================ EDGY_TEXT_KW - Edge ngram with keyword tokenizer (whole field as one token) Use for: autocomplete on exact field content ============================================================================ --> <fieldType name="edgy_text_kw" class="solr.TextField" positionIncrementGap="100"> <analyzer type="index"> <charFilter class="solr.HTMLStripCharFilterFactory"/> <tokenizer class="solr.KeywordTokenizerFactory"/> <filter class="solr.ASCIIFoldingFilterFactory" preserveOriginal="true"/> <filter class="solr.WordDelimiterGraphFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="1" catenateNumbers="1" catenateAll="1" splitOnNumerics="1" splitOnCaseChange="1" preserveOriginal="1" protected="protwords.txt"/> <filter class="solr.FlattenGraphFilterFactory"/> <filter class="solr.LowerCaseFilterFactory"/> <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt"/> <filter class="solr.PatternReplaceFilterFactory" pattern="([^a-z0-9])" replacement="" replace="all"/> <filter class="solr.EdgeNGramFilterFactory" minGramSize="1" maxGramSize="25"/> </analyzer> <analyzer type="query"> <charFilter class="solr.HTMLStripCharFilterFactory"/> <tokenizer class="solr.KeywordTokenizerFactory"/> <filter class="solr.ASCIIFoldingFilterFactory" preserveOriginal="true"/> <filter class="solr.WordDelimiterGraphFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="1" catenateNumbers="1" catenateAll="1" splitOnCaseChange="1" preserveOriginal="1" protected="protwords.txt"/> <filter class="solr.LowerCaseFilterFactory"/> <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt"/> <filter class="solr.PatternReplaceFilterFactory" pattern="([^a-z0-9])" replacement="" replace="all"/> <!-- No EdgeNGram on query side - we want exact prefix match --> </analyzer> </fieldType> <!-- ============================================================================ EDGY_TEXT_WS - Edge ngram with whitespace tokenizer (each word separate) Use for: autocomplete on individual words ============================================================================ --> <fieldType name="edgy_text_ws" class="solr.TextField" positionIncrementGap="100"> <analyzer type="index"> <charFilter class="solr.HTMLStripCharFilterFactory"/> <tokenizer class="solr.WhitespaceTokenizerFactory"/> <filter class="solr.ASCIIFoldingFilterFactory" preserveOriginal="true"/> <filter class="solr.WordDelimiterGraphFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="1" catenateNumbers="1" catenateAll="1" splitOnCaseChange="1" preserveOriginal="1" protected="protwords.txt"/> <filter class="solr.FlattenGraphFilterFactory"/> <filter class="solr.LowerCaseFilterFactory"/> <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt"/> <filter class="solr.PatternReplaceFilterFactory" pattern="([^a-z0-9])" replacement="" replace="all"/> <filter class="solr.EdgeNGramFilterFactory" minGramSize="1" maxGramSize="25"/> </analyzer> <analyzer type="query"> <charFilter class="solr.HTMLStripCharFilterFactory"/> <tokenizer class="solr.WhitespaceTokenizerFactory"/> <filter class="solr.ASCIIFoldingFilterFactory" preserveOriginal="true"/> <filter class="solr.WordDelimiterGraphFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="1" catenateNumbers="1" catenateAll="1" splitOnCaseChange="1" preserveOriginal="1" protected="protwords.txt"/> <filter class="solr.LowerCaseFilterFactory"/> <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt"/> <filter class="solr.PatternReplaceFilterFactory" pattern="([^a-z0-9])" replacement="" replace="all"/> </analyzer> </fieldType> <!-- ============================================================================ TEXT_GENERAL_PHONETIC - For fuzzy/phonetic matching Use for: "sounds like" search, name matching, typo tolerance WARNING: High index size cost, use sparingly ============================================================================ --> <fieldType name="text_general_phonetic" class="solr.TextField" positionIncrementGap="100"> <analyzer type="index"> <charFilter class="solr.HTMLStripCharFilterFactory"/> <tokenizer class="solr.WhitespaceTokenizerFactory"/> <filter class="solr.LowerCaseFilterFactory"/> <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt"/> <filter class="solr.WordDelimiterGraphFilterFactory" generateWordParts="1" generateNumberParts="1" splitOnCaseChange="1" splitOnNumerics="1" preserveOriginal="1"/> <filter class="solr.FlattenGraphFilterFactory"/> <filter class="solr.ASCIIFoldingFilterFactory" preserveOriginal="true"/> <filter class="solr.PorterStemFilterFactory"/> <filter class="solr.PhoneticFilterFactory" encoder="DoubleMetaphone" inject="true"/> </analyzer> <analyzer type="query"> <charFilter class="solr.HTMLStripCharFilterFactory"/> <tokenizer class="solr.WhitespaceTokenizerFactory"/> <filter class="solr.LowerCaseFilterFactory"/> <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt"/> <filter class="solr.WordDelimiterGraphFilterFactory" generateWordParts="1" generateNumberParts="1" splitOnCaseChange="1" splitOnNumerics="1" preserveOriginal="1"/> <filter class="solr.ASCIIFoldingFilterFactory" preserveOriginal="true"/> <filter class="solr.PorterStemFilterFactory"/> <filter class="solr.PhoneticFilterFactory" encoder="DoubleMetaphone" inject="true"/> </analyzer> </fieldType> <!-- ============================================================================ KNN_VECTOR - Dense vector field for semantic search vectorDimension must match your embedding model output size similarityFunction: cosine is standard for normalized embeddings ============================================================================ --> <fieldType name="knn_vector" class="solr.DenseVectorField" vectorDimension="1024" similarityFunction="cosine" /> <!-- ============================================================================ PRIMITIVE TYPES - Using modern "p" prefix types (point-based) These are faster than the old Trie types ============================================================================ --> <fieldType name="string" class="solr.StrField" sortMissingLast="true" docValues="true"/> <fieldType name="boolean" class="solr.BoolField" sortMissingLast="true"/> <!-- Point-based numeric types (Solr 7+, faster than Trie) --> <fieldType name="pint" class="solr.IntPointField" docValues="true"/> <fieldType name="pfloat" class="solr.FloatPointField" docValues="true"/> <fieldType name="plong" class="solr.LongPointField" docValues="true"/> <fieldType name="pdouble" class="solr.DoublePointField" docValues="true"/> <fieldType name="pdate" class="solr.DatePointField" docValues="true"/> <!-- Legacy Trie types - keep for backward compatibility if needed --> <fieldType name="int" class="solr.IntPointField" docValues="true"/> <fieldType name="float" class="solr.FloatPointField" docValues="true"/> <fieldType name="long" class="solr.LongPointField" docValues="true"/> <fieldType name="double" class="solr.DoublePointField" docValues="true"/> <fieldType name="date" class="solr.DatePointField" docValues="true"/> <fieldType name="tint" class="solr.IntPointField" docValues="true"/> <fieldType name="tfloat" class="solr.FloatPointField" docValues="true"/> <fieldType name="tlong" class="solr.LongPointField" docValues="true"/> <fieldType name="tdouble" class="solr.DoublePointField" docValues="true"/> <fieldType name="tdate" class="solr.DatePointField" docValues="true"/> <!-- ============================================================================ SPECIAL TYPES ============================================================================ --> <!-- Location for geo queries --> <fieldType name="location" class="solr.LatLonPointSpatialField" docValues="true"/> <!-- Ignored - for fields you want to accept but not index/store --> <fieldType name="ignored" class="solr.StrField" indexed="false" stored="false" multiValued="true"/> </schema>
Related Documentation
Data Ingestion
Push JSON documents with these fields straight into your index.
Facet Filters
Turn suffixed fields into list, slider and date-range filters on the search page.
Configuration Files
Edit schema.xml, synonyms, stopwords and protected words in the browser.
Hybrid Search
How the embeddings field and keyword fields are fused into one ranking.
Text Analysis Guide
Worked examples of stemming, synonyms and accent folding on real queries.
API Reference
Every endpoint that reads or writes these fields.