![]() |
VOOZH | about |
dotnet add package Zyknow.Abp.Lucene.Domain.Shared --version 10.0.0-preview.4
NuGet\Install-Package Zyknow.Abp.Lucene.Domain.Shared -Version 10.0.0-preview.4
<PackageReference Include="Zyknow.Abp.Lucene.Domain.Shared" Version="10.0.0-preview.4" />
<PackageVersion Include="Zyknow.Abp.Lucene.Domain.Shared" Version="10.0.0-preview.4" />Directory.Packages.props
<PackageReference Include="Zyknow.Abp.Lucene.Domain.Shared" />Project file
paket add Zyknow.Abp.Lucene.Domain.Shared --version 10.0.0-preview.4
#r "nuget: Zyknow.Abp.Lucene.Domain.Shared, 10.0.0-preview.4"
#:package Zyknow.Abp.Lucene.Domain.Shared@10.0.0-preview.4
#addin nuget:?package=Zyknow.Abp.Lucene.Domain.Shared&version=10.0.0-preview.4&prereleaseInstall as a Cake Addin
#tool nuget:?package=Zyknow.Abp.Lucene.Domain.Shared&version=10.0.0-preview.4&prereleaseInstall as a Cake Tool
| English
An ABP module integrating Lucene.NET to provide configurable full-text search, indexing, filtering and highlighting.
PerTenantIndex)./api/lucene/search/{entity})/api/lucene/search-many)ILuceneFilterProvider (Application layer)ConfigureLucene via ForceFilter(...) (always applied as MUST, and supports DI via IServiceProvider)ExcludeFromIndexWhen(...) to prevent indexing certain entities (and try to delete old docs by id when an entity becomes excluded)10.0.0-preview.2net10.010.0.04.8.0-beta00017You can reference projects directly, or use NuGet packages (recommended in host applications).
Typical host layers:
Zyknow.Abp.Lucene.ApplicationZyknow.Abp.Lucene.EntityFrameworkCoreZyknow.Abp.Lucene.HttpApiExample (NuGet):
dotnet add package Zyknow.Abp.Lucene.HttpApi --version 10.0.0-preview.2
dotnet add package Zyknow.Abp.Lucene.EntityFrameworkCore --version 10.0.0-preview.2
DependsOn:
ZyknowLuceneApplicationModuleZyknowLuceneEntityFrameworkCoreModule (if using EF Core auto indexing)ZyknowLuceneHttpApiModule (if exposing REST endpoints)If you want automatic indexing based on EF Core SaveChanges, your DbContext should inherit LuceneAbpDbContext<TDbContext> so the EF interceptor is wired automatically:
// 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:
LuceneEfChangeInterceptor via DbContextOptionsBuilder.AddInterceptors(...).LuceneOptions.EnableAutoIndexingEvents (default true).The module only indexes entity types registered in LuceneOptions.ConfigureLucene(...).
// 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().Store()); // store if you want it in Payload
});
});
});
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 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.
If you prefer to centralize filters together with the entity schema, you can use ForceFilter(...).
Occur.MUSTIServiceProvider, so you can resolve dependencies (e.g., ICurrentUser, permission stores, tenant providers, etc.)Example: force filter by allowed LibraryId list and exclude missing entries:
using Lucene.Net.Search;
using Zyknow.Abp.Lucene.Filtering;
model.Entity<Medium>(e =>
{
// Filterable fields must be searchable (e.g., Keyword()).
e.Field(x => x.LibraryId, f => f.Keyword());
e.Field(x => x.IsMissing, f => f.Keyword());
e.ForceFilter<SearchQueryInput>((sp, ctx) =>
{
var permissionStore = sp.GetRequiredService<IMyLibraryPermissionService>();
var allowedIds = permissionStore.GetAllowedLibraryIds();
var must = new BooleanQuery
{
{ LuceneQueries.In(nameof(Medium.LibraryId), allowedIds), Occur.MUST },
// if you index bool as string, use "False"/"True" accordingly
{ LuceneQueries.Term(nameof(Medium.IsMissing), "False"), Occur.MUST }
};
return must;
});
});
Use ExcludeFromIndexWhen(...) to skip indexing certain entities (and try to delete any existing doc by id when an entity becomes excluded):
model.Entity<Medium>(e =>
{
e.Field(x => x.Title, f => f.Store());
e.ExcludeFromIndexWhen((sp, x) => x.IsDeleted);
});
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 | net10.0 net10.0 is compatible. 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. |
Showing the top 5 NuGet packages that depend on Zyknow.Abp.Lucene.Domain.Shared:
| Package | Downloads |
|---|---|
|
Zyknow.Abp.Lucene.Application
ABP 框架的 Lucene.Net 集成,提供索引、查询、过滤与高亮能力。 |
|
|
Zyknow.Abp.Lucene.Application.Contracts
ABP 框架的 Lucene.Net 集成,提供索引、查询、过滤与高亮能力。 |
|
|
Zyknow.Abp.Lucene.HttpApi
ABP 框架的 Lucene.Net 集成,提供索引、查询、过滤与高亮能力。 |
|
|
Zyknow.Abp.Lucene.Domain
ABP 框架的 Lucene.Net 集成,提供索引、查询、过滤与高亮能力。 |
|
|
Zyknow.Abp.Lucene.EntityFrameworkCore
ABP 框架的 Lucene.Net 集成,提供索引、查询、过滤与高亮能力。 |
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 10.0.0-preview.4 | 118 | 1/7/2026 |
| 10.0.0-preview.3 | 109 | 12/29/2025 |
| 10.0.0-preview.2 | 79 | 12/27/2025 |
| 10.0.0-preview.1 | 487 | 12/1/2025 |
| 1.0.0-preview.8 | 255 | 11/14/2025 |
| 1.0.0-preview.7 | 188 | 10/28/2025 |
| 1.0.0-preview.6 | 172 | 10/27/2025 |
| 1.0.0-preview.5 | 152 | 10/24/2025 |
| 1.0.0-preview.4 | 150 | 10/24/2025 |
| 1.0.0-preview.3 | 175 | 10/23/2025 |
| 1.0.0-preview.2 | 174 | 10/21/2025 |
| 1.0.0-preview.1 | 165 | 10/21/2025 |