Skip to main content
AI/MLCrestApps

orchardcore-elasticsearch

Skill for configuring Elasticsearch in Orchard Core. Covers Elasticsearch setup and Docker deployment, connection configuration, analyzers and token filters, index creation recipe steps, query types, comparison with Lucene, field mapping, custom data indexing, and Elasticsearch-specific configuration options. Use this skill when requests mention Orchard Core Elasticsearch, Configure Elasticsearch, Enabling Elasticsearch Features, Elasticsearch Connection Configuration, Docker Deployment, Creating an Elasticsearch Index Profile (Recommended), or closely related Orchard Core implementation, setup, extension, or troubleshooting work. Strong matches include work with OrchardCore.Elasticsearch, OrchardCore.Search, OrchardCore.Indexing, OrchardCore.Modules. It also helps with Docker Deployment, Creating an Elasticsearch Index Profile (Recommended), Legacy Index Creation (Obsolete), plus the code patterns, admin flows, recipe steps, and referenced examples captured in this skill.

Stars
13
Source
CrestApps/CrestApps.AgentSkills
Updated
2026-05-29
Slug
CrestApps--CrestApps.AgentSkills--orchardcore-elasticsearch
View on GitHubRaw SKILL.md

// install — copy + paste into any project

mkdir -p .claude/skills && curl -fsSL https://raw.githubusercontent.com/CrestApps/CrestApps.AgentSkills/HEAD/plugins/orchardcore/skills/orchardcore-elasticsearch/SKILL.md -o .claude/skills/orchardcore-elasticsearch.md

Drops the SKILL.md into .claude/skills/orchardcore-elasticsearch.md. Works with Claude Code, Cursor, and any agent that loads SKILL.md files from .claude/skills/.

Orchard Core Elasticsearch - Prompt Templates

Configure Elasticsearch

You are an Orchard Core expert. Generate code and configuration for Elasticsearch-based search in Orchard Core.

Guidelines

  • Enable OrchardCore.Elasticsearch to manage Elasticsearch indices.
  • Configure the Elasticsearch connection in appsettings.json under the OrchardCore_Elasticsearch section.
  • Use the CreateOrUpdateIndexProfile recipe step to create indexes (preferred over the obsolete ElasticIndexSettings step).
  • Use the ResetIndex recipe step to restart indexing without deleting entries (preferred over the obsolete elastic-index-reset step).
  • Use the RebuildIndex recipe step to delete and recreate indexes (preferred over the obsolete elastic-index-rebuild step).
  • Elasticsearch uses the Elasticsearch Query DSL for queries.
  • Elasticsearch automatically maps string fields to both text and keyword types.
  • Supported connection types: SingleNodeConnectionPool, CloudConnectionPool, StaticConnectionPool, SniffingConnectionPool, StickyConnectionPool.
  • Supported authentication types: Basic, ApiKey, Base64ApiKey, KeyIdAndKey.
  • Custom analyzers and token filters are defined in appsettings.json.
  • Both Lucene and Elasticsearch modules can be enabled simultaneously.
  • All recipe JSON must be wrapped in { "steps": [...] }.
  • All C# classes must use the sealed modifier.

Enabling Elasticsearch Features

{
  "steps": [
    {
      "name": "Feature",
      "enable": [
        "OrchardCore.Search",
        "OrchardCore.Elasticsearch",
        "OrchardCore.Indexing"
      ],
      "disable": []
    }
  ]
}

Elasticsearch Connection Configuration

Configure the connection in appsettings.json:

{
  "OrchardCore_Elasticsearch": {
    "ConnectionType": "SingleNodeConnectionPool",
    "Url": "http://localhost",
    "Ports": [9200],
    "AuthenticationType": "Basic",
    "Username": "admin",
    "Password": "admin",
    "CertificateFingerprint": "",
    "EnableDebugMode": false,
    "EnableHttpCompression": true,
    "IndexPrefix": "",
    "Analyzers": {
      "standard": {
        "type": "standard"
      }
    }
  }
}
Property Description
ConnectionType Connection pool type. Use CloudConnectionPool for Elastic Cloud.
Url Elasticsearch server URL.
Ports Array of ports for the Elasticsearch nodes.
AuthenticationType Basic, ApiKey, Base64ApiKey, or KeyIdAndKey.
Username / Password Required for Basic authentication.
ApiKey Required for ApiKey authentication.
Base64ApiKey Required for Base64ApiKey authentication.
CloudId Required for CloudConnectionPool connection type.
KeyId / Key Required for KeyIdAndKey authentication.
CertificateFingerprint TLS certificate fingerprint (not needed for CloudConnectionPool).
EnableDebugMode Enables debug output for troubleshooting.
EnableHttpCompression Enables gzip compression for requests.
IndexPrefix Prefix applied to all index names (useful for environment isolation).

Docker Deployment

For local development, deploy Elasticsearch with Docker Compose.

WSL2 prerequisite — set vm.max_map_count in %userprofile%\.wslconfig:

[wsl2]
kernelCommandLine = "sysctl.vm.max_map_count=262144"

Then restart WSL: wsl --shutdown

Creating an Elasticsearch Index Profile (Recommended)

{
  "steps": [
    {
      "name": "CreateOrUpdateIndexProfile",
      "indexes": [
        {
          "Name": "BlogPostsES",
          "IndexName": "blogposts",
          "ProviderName": "Elasticsearch",
          "Type": "Content",
          "Properties": {
            "ContentIndexMetadata": {
              "IndexLatest": false,
              "IndexedContentTypes": ["BlogPost"],
              "Culture": "any"
            },
            "ElasticsearchIndexMetadata": {
              "AnalyzerName": "standard",
              "StoreSourceData": true
            },
            "ElasticsearchDefaultQueryMetadata": {
              "QueryAnalyzerName": "standard",
              "SearchType": "",
              "DefaultQuery": "",
              "DefaultSearchFields": [
                "Content.ContentItem.FullText"
              ]
            }
          }
        }
      ]
    }
  ]
}
Property Description
AnalyzerName Index-time analyzer (e.g., "standard").
StoreSourceData Stores the _source data in Elasticsearch.
QueryAnalyzerName Analyzer used when querying this index.
SearchType "" (default multi-match), "query_string", or "custom".
DefaultQuery Custom query template when SearchType is "custom". Use {{ term }} for the search term.
DefaultSearchFields Array of fields to search across.

Legacy Index Creation (Obsolete)

{
  "steps": [
    {
      "name": "ElasticIndexSettings",
      "Indices": [
        {
          "Search": {
            "AnalyzerName": "standard",
            "IndexLatest": false,
            "IndexedContentTypes": [
              "Article",
              "BlogPost"
            ]
          }
        }
      ]
    }
  ]
}

Reset Elasticsearch Index

{
  "steps": [
    {
      "name": "ResetIndex",
      "indexNames": [
        "BlogPostsES"
      ]
    }
  ]
}

Rebuild Elasticsearch Index

{
  "steps": [
    {
      "name": "RebuildIndex",
      "indexNames": [
        "BlogPostsES"
      ]
    }
  ]
}

Creating an Elasticsearch Query via Recipe

{
  "steps": [
    {
      "Source": "Elasticsearch",
      "Name": "RecentBlogPosts",
      "Index": "Search",
      "Template": "{ \"query\": { \"match_all\": {} }, \"size\": 10 }",
      "ReturnContentItems": true
    }
  ]
}

Configuring Analyzers

Define built-in and custom analyzers in appsettings.json:

{
  "OrchardCore_Elasticsearch": {
    "Analyzers": {
      "standard": {
        "type": "standard"
      },
      "stop": {
        "type": "stop",
        "stopwords": ["a", "the", "and", "or"]
      },
      "english_analyzer": {
        "type": "custom",
        "tokenizer": "standard",
        "filter": ["lowercase", "stop"],
        "char_filter": ["html_strip"]
      }
    }
  }
}

Configuring Token Filters

Define custom token filters in appsettings.json and reference them from analyzers:

{
  "OrchardCore_Elasticsearch": {
    "TokenFilters": {
      "english_stop": {
        "type": "stop",
        "stopwords": "_english_"
      }
    },
    "Analyzers": {
      "my_new_analyzer": {
        "type": "custom",
        "tokenizer": "standard",
        "filter": ["english_stop"]
      }
    }
  }
}

Custom Query with Search Highlights

When using "custom" search type, define a query with highlighting using the Liquid {{ term }} placeholder:

{
  "query": {
    "multi_match": {
      "fields": ["Content.ContentItem.FullText"],
      "query": "{{ term }}",
      "fuzziness": "AUTO"
    }
  },
  "highlight": {
    "pre_tags": ["<span style='background-color: #FFF3CD;'>"],
    "post_tags": ["</span>"],
    "fields": {
      "Content.ContentItem.FullText": {
        "fragment_size": 150,
        "number_of_fragments": 3
      }
    }
  }
}

Highlight requests require StoreSourceData to be enabled on the index.

Web APIs

api/elasticsearch/content — Executes a query and returns content items.

Verbs: POST and GET

Parameter Example Description
indexName "search" The name of the index to query.
query { "query": { "match_all": {} }, "size": 10 } JSON query object.
parameters { "size": 3 } JSON parameters object.

api/elasticsearch/documents — Executes a query and returns Elasticsearch documents (stored fields only).

Same parameters as api/elasticsearch/content.

Returning Specific Fields

Elasticsearch can return specific fields instead of full source:

{
  "query": {
    "match_all": {}
  },
  "fields": [
    "ContentItemId.keyword",
    "ContentItemVersionId.keyword"
  ],
  "_source": false
}

Indexing Custom Data

Register a custom indexing source in Startup.cs:

using OrchardCore.Modules;

namespace MyModule;

[Feature("MyModule.CustomElasticsearchIndex")]
public sealed class Startup : StartupBase
{
    public override void ConfigureServices(IServiceCollection services)
    {
        services.AddElasticsearchIndexingSource("CustomSource", o =>
        {
            o.DisplayName = S["Custom Source"];
            o.Description = S["Create an Elasticsearch index based on a custom data source."];
        });
    }
}

Elasticsearch vs Lucene Field Mapping

Elasticsearch automatically maps string fields to both text and keyword types. Lucene uses explicit StringField (keyword) and TextField (text) types.

Lucene Elasticsearch Description Search Query Type
StringField keyword Indexed as a single token, not tokenized. Term-level queries.
TextField text Indexed and tokenized for full-text search. Full-text queries.
StoredField _source Original value stored, not analyzed. Term-level queries.

Adapt queries when switching between Lucene and Elasticsearch — field types may differ for the same field name.