Skip to content

birko/Birko.Data.ElasticSearch

Repository files navigation

Birko.Data.ElasticSearch

Elasticsearch implementation for the Birko Framework providing full-text search and document storage.

Features

  • Full-text search with tokenization, stemming, and relevance scoring
  • Document-based CRUD operations (sync/async)
  • Bulk operations optimized for Elasticsearch
  • Aggregations and pagination
  • Search result highlighting
  • Index mapping and management

Installation

dotnet add package Birko.Data.ElasticSearch

Dependencies

  • Birko.Data.Core (AbstractModel)
  • Birko.Data.Stores (store interfaces, Settings)
  • NEST (Elasticsearch .NET client)

Usage

using Birko.Data.ElasticSearch.Stores;

var settings = new ElasticSearchSettings
{
    Uri = "http://localhost:9200",
    IndexName = "products",
    Username = "elastic",
    Password = "password"
};

var store = new ElasticSearchStore<Product>(settings);
var id = store.Create(product);

Search

var response = Client.Search<Product>(s => s
    .Index(Settings.IndexName)
    .Query(q => q.MultiMatch(m => m
        .Query("search term")
        .Fields(f => f.Field(p => p.Name).Field(p => p.Description))
    ))
    .From(0).Size(20)
    .Sort(sort => sort.Descending(f => f.CreatedAt))
);

API Reference

Stores

  • ElasticSearchStore<T> - Sync store
  • ElasticSearchBulkStore<T> - Bulk operations
  • AsyncElasticSearchStore<T> - Async store
  • AsyncElasticSearchBulkStore<T> - Async bulk store

Repositories

  • ElasticSearchRepository<T> / ElasticSearchBulkRepository<T>
  • AsyncElasticSearchRepository<T> / AsyncElasticSearchBulkRepository<T>

Index Management

using Birko.Data.ElasticSearch.IndexManagement;

var manager = new IndexManager(client);

// Create an index with settings and mappings
await manager.CreateIndexAsync("products-v2", new
{
    settings = new { number_of_shards = 2, number_of_replicas = 1 },
    mappings = new { properties = new { Name = new { type = "text" } } }
});

// Get index information
IndexInfo info = await manager.GetIndexInfoAsync("products-v2");
Console.WriteLine($"Docs: {info.DocumentCount}, Size: {info.Size}");

// Manage aliases
await manager.AddAliasAsync("products-v2", "products");
await manager.RemoveAliasAsync("products-v1", "products");

// Refresh, flush, clear cache
await manager.RefreshIndexAsync("products-v2");
await manager.FlushIndexAsync("products-v2");
await manager.ClearCacheAsync("products-v2");

Uniform IIndexManager Interface

using Birko.Data.ElasticSearch.IndexManagement;
using Birko.Data.Patterns.IndexManagement;

// Adapter wraps existing IndexManager with IIndexManager interface
var adapter = new ElasticSearchIndexManagerAdapter(client);

// Same API as MongoDB, RavenDB, SQL providers
await adapter.CreateAsync(new IndexDefinition
{
    Name = "products-v2",
    Properties = new Dictionary<string, object>
    {
        ["NumberOfShards"] = 2,
        ["NumberOfReplicas"] = 1
    }
});
var indexes = await adapter.ListAsync();
var info = await adapter.GetInfoAsync("products-v2");

// Access full ES-specific capabilities via .Native
var native = adapter.Native;
await native.CreateAliasAsync("products-v2", "products");
await native.SwapAliasAsync("products", "products-v1", "products-v2");

Reindexing

using Birko.Data.ElasticSearch.IndexManagement;

var reindexHelper = new ReindexHelper(client);

// Basic reindex
ReindexResult result = await reindexHelper.ReindexAsync("products-v1", "products-v2");
Console.WriteLine($"Indexed {result.DocumentsIndexed} docs in {result.Duration}");

// Reindex with a Painless script transformation
ReindexResult scriptResult = await reindexHelper.ReindexWithScriptAsync(
    "products-v1", "products-v2",
    "ctx._source.price = ctx._source.price * 1.1"
);

// Zero-downtime reindex via alias swap
ReindexResult swapResult = await reindexHelper.ZeroDowntimeReindexAsync(
    "products-v1", "products-v2", "products"
);

Search Result Highlighting

Highlight matching terms in search results:

using Birko.Data.ElasticSearch.Stores;

var response = Client.Search<Product>(s => s
    .Index(Settings.IndexName)
    .Query(q => q.MultiMatch(m => m
        .Query("search term")
        .Fields(f => f.Field(p => p.Name).Field(p => p.Description))
    ))
    .Highlight(h => h
        .PreTags("<em>")
        .PostTags("</em>")
        .Fields(
            f => f.Field(p => p.Name),
            f => f.Field(p => p.Description)
        )
    )
);

foreach (var hit in response.Hits)
{
    var highlights = hit.Highlight;
    if (highlights.ContainsKey("name"))
    {
        Console.WriteLine($"Name: {string.Join("...", highlights["name"])}");
    }
}

Related Projects

Filter-Based Bulk Operations

ElasticSearch stores support native filter-based update and delete:

  • Update(filter, PropertyUpdate<T>) — Uses UpdateByQuery with Painless scripts generated from property assignments
  • Delete(filter) — Uses DeleteByQuery with filter converted via ParseExpression()
  • Update(filter, Action<T>) — Read-modify-save fallback for complex mutations

License

Part of the Birko Framework.

About

No description or website provided.

Topics

Resources

License

MIT, MIT licenses found

Licenses found

MIT
LICENSE
MIT
License.md

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages