Skip to main content
net8.0net10.0

A lucene style query parser that is extensible and allows additional syntax features.

Published
Feb 27, 2026
7mo ago
Total Downloads
672.7K
672,662

Install

dotnet add package Foundatio.Parsers.ElasticQueries --version 7.18.0-beta4
ProductVersions
.NET
net10.0net8.0

README

FoundatioFoundatio

Build status NuGet Version feedz.io Discord

An extensible Lucene-style query parser with support for Elasticsearch and SQL/Entity Framework Core. Build dynamic search APIs, custom dashboards, and powerful query interfaces.

Documentation

Read the full documentation

Installation

# Core Lucene parser
dotnet add package Foundatio.Parsers.LuceneQueries

# Elasticsearch integration
dotnet add package Foundatio.Parsers.ElasticQueries

# SQL/EF Core integration
dotnet add package Foundatio.Parsers.SqlQueries

Quick Start

Parse and Inspect Queries

using Foundatio.Parsers.LuceneQueries;
using Foundatio.Parsers.LuceneQueries.Visitors;

var parser = new LuceneQueryParser();
var result = parser.Parse("field:[1 TO 2]");

// Debug the AST structure
Console.WriteLine(DebugQueryVisitor.Run(result));

Output from DebugQueryVisitor:

Group:
  Left - Term:
      TermMax: 2
      TermMin: 1
      MinInclusive: True
      MaxInclusive: True
      Field:
          Name: field

Regenerate the original query:

string query = GenerateQueryVisitor.Run(result);
// Output: "field:[1 TO 2]"

Build Elasticsearch Queries

using Foundatio.Parsers.ElasticQueries;

var parser = new ElasticQueryParser(c => c
    .UseMappings(client, "my-index")
    .UseFieldMap(new Dictionary<string, string> {
        { "user", "data.user.identity" }
    }));

// Build NEST QueryContainer
var query = await parser.BuildQueryAsync("user:john AND status:active");

// Build aggregations
var aggs = await parser.BuildAggregationsAsync("terms:(status min:created max:created)");

// Build sort
var sort = await parser.BuildSortAsync("-created +name");

Build SQL/EF Core Queries

using Foundatio.Parsers.SqlQueries;

var parser = new SqlQueryParser(c => c
    .SetDefaultFields(new[] { "Name", "Description" }));

var context = parser.GetContext(db.Products.EntityType);
string dynamicLinq = await parser.ToDynamicLinqAsync("status:active AND price:>100", context);

var results = await db.Products
    .Where(parser.ParsingConfig, dynamicLinq)
    .ToListAsync();

Features

Query Syntax

  • Term queries: field:value, field:"quoted phrase"
  • Range queries: field:[1 TO 10], field:>100, field:>=2024-01-01
  • Boolean operators: AND, OR, NOT, +, -
  • Wildcards: field:val*, field:va?ue
  • Existence: _exists_:field, _missing_:field
  • Date math: created:[now-7d TO now]
  • Geo queries: location:75044~75mi

Full Query Syntax Reference

Aggregations

  • Metrics: min, max, avg, sum, stats, cardinality, percentiles
  • Buckets: terms, date, histogram, geogrid, missing
  • Nested: terms:(category min:price max:price)

Full Aggregation Syntax Reference

Field Aliases

Map user-friendly names to actual field paths:

var parser = new ElasticQueryParser(c => c
    .UseFieldMap(new Dictionary<string, string> {
        { "user", "data.user.identity" },
        { "created", "metadata.createdAt" }
    }));

Field Aliases Guide

Query Includes

Define reusable query macros:

var parser = new ElasticQueryParser(c => c
    .UseIncludes(new Dictionary<string, string> {
        { "active", "status:active AND deleted:false" },
        { "recent", "created:[now-7d TO now]" }
    }));

// Expands @include:active inline
var query = await parser.BuildQueryAsync("@include:active AND category:electronics");

Query Includes Guide

Validation

Validate and restrict queries:

var parser = new ElasticQueryParser(c => c
    .SetValidationOptions(new QueryValidationOptions {
        AllowedFields = { "status", "name", "created" },
        AllowLeadingWildcards = false,
        AllowedMaxNodeDepth = 10
    }));

var result = await parser.ValidateQueryAsync(userQuery);
if (!result.IsValid)
    return BadRequest(result.Message);

Validation Guide

Visitor Pattern

Extend with custom query transformations:

public class CustomVisitor : ChainableQueryVisitor
{
    public override async Task VisitAsync(TermNode node, IQueryVisitorContext context)
    {
        // Custom transformation logic
        await base.VisitAsync(node, context);
    }
}

var parser = new ElasticQueryParser(c => c
    .AddVisitor(new CustomVisitor(), priority: 100));

Visitors Guide

Use Cases

  • Dynamic Search APIs - Let users build complex queries
  • Custom Dashboards - User-defined aggregations and visualizations
  • Saved Searches - Store and reuse query fragments
  • Multi-tenant Filtering - Apply tenant filters transparently
  • Query Translation - Parse once, output to multiple backends

Getting Started (Development)

  1. Clone the repository
  2. Open Foundatio.Parsers.slnx in Visual Studio or VS Code
  3. Build: dotnet build
  4. Test: dotnet test

Thanks to all the people who have contributed

contributors

Changes from Previous Version

No structural changes between v7.18.0-beta3 and v7.18.0-beta4.

Adoption Assessment

A verified publisher signal is available. Assess fit from the package's supported frameworks, license and dependency graph rather than popularity alone.

This version is marked prerelease. Validate its API and upgrade path before production use.Compatibility metadata lists 2 target frameworks; confirm the exact target used by your application.

Related Guides & Workflows

Learn how to evaluate, integrate, or audit this package in your .NET project.