![]() |
VOOZH | about |
dotnet add package Zyknow.Abp.Lucene.EntityFrameworkCore --version 1.0.0-preview.8
NuGet\Install-Package Zyknow.Abp.Lucene.EntityFrameworkCore -Version 1.0.0-preview.8
<PackageReference Include="Zyknow.Abp.Lucene.EntityFrameworkCore" Version="1.0.0-preview.8" />
<PackageVersion Include="Zyknow.Abp.Lucene.EntityFrameworkCore" Version="1.0.0-preview.8" />Directory.Packages.props
<PackageReference Include="Zyknow.Abp.Lucene.EntityFrameworkCore" />Project file
paket add Zyknow.Abp.Lucene.EntityFrameworkCore --version 1.0.0-preview.8
#r "nuget: Zyknow.Abp.Lucene.EntityFrameworkCore, 1.0.0-preview.8"
#:package Zyknow.Abp.Lucene.EntityFrameworkCore@1.0.0-preview.8
#addin nuget:?package=Zyknow.Abp.Lucene.EntityFrameworkCore&version=1.0.0-preview.8&prereleaseInstall as a Cake Addin
#tool nuget:?package=Zyknow.Abp.Lucene.EntityFrameworkCore&version=1.0.0-preview.8&prereleaseInstall as a Cake Tool
| English
An ABP module based on Lucene.NET that provides configurable full-text search capabilities for your system.
Zyknow.Abp.Lucene.* in your host applicationDependsOnLuceneAbpDbContext<TDbContext> so the Lucene EF change interceptor is wired automatically. Example:// Host application's EF Core DbContext
public class MyDbContext : LuceneAbpDbContext<MyDbContext>
{
public MyDbContext(DbContextOptions<MyDbContext> options) : base(options) { }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// ... your entity configurations
}
}
Notes:
LuceneAbpDbContext<TDbContext>.The module subscribes to ABP local entity events internally and only listens to entity types registered in ConfigureLucene, achieving automatic index maintenance.
// using Zyknow.Abp.Lucene.Options;
Configure<LuceneOptions>(opt =>
{
opt.IndexRootPath = Path.Combine(AppContext.BaseDirectory, "lucene-index");
opt.PerTenantIndex = true; // default true
opt.AnalyzerFactory = AnalyzerFactories.IcuGeneral;
opt.ConfigureLucene(model =>
{
model.Entity<Book>(e =>
{
e.Field(x => x.Title, f => f.Store());
e.Field(x => x.Author, f => f.Store());
e.Field(x => x.Code, f => f.Keyword());
});
});
});
api/lucene/search/{entity}api/lucene/search-manyapi/lucene/rebuild/{entity}api/lucene/rebuild-and-index/{entity}?batchSize=1000api/lucene/count/{entity}SearchResultDto: TotalCount and Items.SearchHitDto) contains:
EntityId: document primary key (from each entity descriptor's IdFieldName)Score: relevance scorePayload: stored field key-value pairs. In multi-entity aggregation, it also contains Payload["__IndexName"] to indicate the source entity index name.Notes
LuceneOptions.LuceneQuery:
MultiFieldMode: AND/OR (default OR).FuzzyMaxEdits: edit distance for fuzzy matching (default 1).PerTenantIndex), requests search under the current tenant's index directory.Within EntitySearchBuilder<T>.Field(expr, configure) or ValueField(selector, configure), you can use the following methods to control how the field is indexed and retrieved:
Store(bool enabled = true)
false. Call f.Store() to enable.LuceneSearchAppService can read this value from the hit document and put it into the result Payload.Name(string name)
ValueField defaults to "Value".Keyword()
StringField; otherwise uses TextField (tokenized).Autocomplete(int minGram = 1, int maxGram = 20)
StoreTermVectors(bool positions = true, bool offsets = true)
TermVector at search time or extend index writing.Depends(Expression<Func<object>> member)
ValueField so the synchronizer can load only necessary columns and compute derived text.model.Entity<Book>(e =>
{
// Property field: tokenized and store original value
e.Field(x => x.Title, f => f.Store());
// Keyword field: no tokenization, exact match, renamed
e.Field(x => x.Code, f => f.Keyword().Name("BookCode"));
// Derived field: declare dependencies to enable automatic projection
e.ValueField(x => $"{x.Author} - {x.Title}", f =>
f.Name("AuthorTitle").Store()
.Depends(() => x.Author)
.Depends(() => x.Title));
});
You can plug custom filters into the search pipeline via ILuceneFilterProvider in the Application layer:
Task<Query?> BuildAsync(SearchFilterContext ctx){ string EntityName, EntitySearchDescriptor Descriptor, SearchQueryInput Input }Query is added with Occur.MUST to the final queryA lightweight LINQ → Lucene mapping helper is provided to write filters with simple LINQ expressions and convert them into Lucene queries:
x => x.Field == value → TermQueryvalues.Contains(x.Field) → multiple TermQuery with BooleanQuery SHOULD + MinimumNumberShouldMatch=1x => x.Field.StartsWith("ab") → PrefixQueryx => x.Field.EndsWith(".jpg") → WildcardQuery("*.jpg")x => x.Field.Contains("foo") → WildcardQuery("*foo*")AndAlso → MUST, OrElse → SHOULDusing System.Linq.Expressions;
using Lucene.Net.Search;
using Volo.Abp.DependencyInjection;
using Zyknow.Abp.Lucene.Filtering;
public class LibraryFilterProvider : ILuceneFilterProvider, IScopedDependency
{
public Task<Query?> BuildAsync(SearchFilterContext ctx)
{
// Assume you get the list of library ids from your request or dependency
var libraryIds = new [] { Guid.Parse("11111111-1111-1111-1111-111111111111"), Guid.Parse("22222222-2222-2222-2222-222222222222") };
Expression<Func<Project, bool>> expr = x => libraryIds.Contains(x.LibraryId);
var query = LinqLucene.Where(ctx.Descriptor, expr);
return Task.FromResult<Query?>(query);
}
private sealed class Project
{
public Guid LibraryId { get; set; }
}
}
Tip: If ctx.Expression is already provided by the caller and this provider returns null, the pipeline will try to convert that expression to a Lucene Query and merge it with MUST.
Term-based range comparisons are lexicographical. Normalize numbers/dates at indexing time (zero-pad, yyyyMMddHHmmss).
When you run multiple writes in parallel within the same HTTP request, not using requiresNew in child tasks may reuse the same UoW and cause errors.
Solution (choose one):
requiresNew: trueBeginParallel insert example for Book (no rebuild): see below.
var tasks = Enumerable.Range(0, threads).Select(async t =>
{
using var uow = uowManager.Begin(new AbpUnitOfWorkOptions { IsTransactional = true }, requiresNew: true);
for (var i = 0; i < perThread; i++)
await bookRepo.InsertAsync(new Book(GuidGenerator.Create(), $"Title-{t}-{i}", $"Author-{t}"), autoSave: true);
await uow.CompleteAsync();
});
await Task.WhenAll(tasks);
Notes:
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0 net9.0 is compatible. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 was computed. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
This package is not used by any NuGet packages.
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 10.0.0-preview.4 | 105 | 1/7/2026 |
| 10.0.0-preview.3 | 90 | 12/29/2025 |
| 10.0.0-preview.2 | 77 | 12/27/2025 |
| 10.0.0-preview.1 | 474 | 12/1/2025 |
| 1.0.0-preview.8 | 259 | 11/14/2025 |
| 1.0.0-preview.7 | 183 | 10/28/2025 |
| 1.0.0-preview.6 | 189 | 10/27/2025 |