Site Search Schema Reference - Fields, Suffixes, Text Analysis

The fields behind site search, and the live schema.xml file

The schema behind site search

Every Opensolr Index has its own schema.xml: the file that says which fields a document has and how each one is searched. An index in a region with site search gets the Opensolr site search schema, and everything that fills or searches it reads the same fields: the crawl of your site, Data Ingestion, the Drupal module, the WordPress plugin, the developer packages and the hosted search page.

The file is yours. You can change it, or replace it with any schema Solr accepts, in Configuration. A schema without the fields described here loses the tools that read them by name.

The pages

How to read a schema
Fields, dynamic fields, field types and the switches on each.
Fields Opensolr adds
What you send, what Opensolr works out from it, and whose value wins.
Core fields
The fields every document has, and what a page read by the crawl also carries.
Add fields with a suffix
Name a field price_f or brand_sm and it exists, with facets, sorting and ranges.
How text is analysed
Why running finds run, and how autocomplete, spelling and the meaning vector work.
What is not in schema.xml
Copy fields, request handlers, field weights, the hybrid parser and facet settings.
Changing the schema
What is safe to change, and what needs your documents sent again.
Check and install the schema
Is an index ready for site search, and how to make it ready.

The file itself

This is the exact schema.xml Opensolr puts on an index in a region with site search, compatible with Solr 9.00 to 10.00. Everything the pages above explain is in here. Scroll through it, or copy it as the start of a schema of your own.

449 lines, last updated 09/02/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>

Schema reference pages

Back to Enterprise Site Search