Files
Baradb/docs/en/fts.md
T
dimgigov ef264d7d69
CI / test (push) Has been cancelled
CI / verify (push) Has been cancelled
Clients CI / build-server (push) Has been cancelled
Clients CI / test-python (push) Has been cancelled
Clients CI / test-javascript (push) Has been cancelled
Clients CI / test-nim (push) Has been cancelled
Clients CI / test-rust (push) Has been cancelled
feat: add unified search engine — HNSW heap-opt, segment index, boolean/phrase/ngram/facet
New src/barabadb/search/ module with 9 components:
- priority_queue.nim: BoundedHeap for O(log n) search
- hnsw_opt.nim: heap-based searchLayer (2.4x faster, 92-99% recall@10)
- inverted.nim: segment-based index with soft-delete and compaction
- phrase.nim: positional phrase + proximity search
- boolean.nim: recursive descent parser (AND/OR/NOT/ranges/wildcards)
- ngram.nim: trigram index for O(1) fuzzy/prefix/wildcard
- stemmer.nim: Porter2 stemmers (EN/BG/DE/FR/RU)
- facet.nim: faceted search with filter pushdown
- engine.nim: UnifiedSearchEngine combining all search types

Performance (dim=128, efConstruction=200):
  N=1K:   0.30ms search, 99.6% recall@10
  N=10K:  1.09ms search, 92.6% recall@10
  N=50K:  2.26ms search, 75.5% recall@10

Includes search benchmarks (benchmarks/search_bench.nim), updated docs
(en/bg fts.md, en/bg search.md), and crossmodal engine integration.
2026-05-30 13:42:08 +03:00

5.4 KiB

Full-Text Search Engine

Inverted index with BM25 and TF-IDF ranking for text search.

Usage

import barabadb/fts/engine

var idx = newInvertedIndex()
idx.addDocument(1, "Nim is a fast programming language")
idx.addDocument(2, "Python is popular for data science")

# BM25 search
let results = idx.search("programming language")

# TF-IDF search
let tfidf = idx.searchTfidf("programming language")

# Fuzzy search (typo tolerance)
let fuzzy = idx.fuzzySearch("programing", maxDistance = 2)

# Wildcard search
let wild = idx.regexSearch("prog*")

Ranking Methods

BM25

Best matching ranking algorithm:

let bm25 = idx.searchBM25("query terms")

TF-IDF

Term Frequency-Inverse Document Frequency:

let tfidf = idx.searchTfidf("query terms")

Search Features

Feature Description
Fuzzy search Levenshtein distance tolerance
Wildcard Prefix, suffix, and infix wildcards
Regex Regular expression patterns
Phrase search Exact phrase matching with slop support
Proximity search Terms within a configurable distance window
Boolean AND, OR, NOT operators with nested expressions
Faceted search Category filtering, counts, and aggregation
Hybrid search Combined full-text + vector (HNSW) with RRF fusion
Segment indexing Incremental indexing with automatic compaction
Field boosting Per-field relevance weights

SQL Interface

Full-text search is also available directly in BaraQL:

-- Create a table with text column
CREATE TABLE articles (id INT PRIMARY KEY, title TEXT, body TEXT);

-- Create an FTS index
CREATE INDEX idx_fts ON articles(body) USING FTS;

-- Search with the @@ operator (BM25 ranking)
SELECT * FROM articles WHERE body @@ 'machine learning';

-- Search with multiple terms
SELECT * FROM articles WHERE body @@ 'quick brown fox';

Multi-Language Support

import barabadb/fts/multilang

# Supported languages: EN, BG, DE, FR, RU
var tokenizer = newTokenizer("bg")  # Bulgarian
let tokens = tokenizer.tokenize("Търсене в пълен текст")

Features per language:

  • Tokenization
  • Stop words
  • Stemming
  • Language detection

The new src/barabadb/search/ module provides a unified search engine with segment-based indexing for high-performance search operations.

UnifiedSearchEngine

import barabadb/search/engine

# Create search engine with default configuration
var engine = newUnifiedSearchEngine()

# Index documents with fields and facets
engine.indexDocument(
  docId = 1,
  text = "Nim is a fast programming language",
  fields = {"title": "Nim Overview"}.toTable,
  facets = {"category": @["programming"], "level": @["beginner"]}.toTable
)

# Basic search
let results = engine.search("programming language", limit = 10)

# Phrase search (exact phrase matching)
let phrase = engine.searchPhrase(@["fast", "programming"], slop = 0)

# Proximity search (terms within distance)
let proximity = engine.searchProximity(@["fast", "language"], maxDistance = 5)

# Boolean queries
let boolResults = engine.searchBoolean("programming AND (fast OR efficient)")
let boolResults2 = engine.searchBoolean("Nim AND NOT Python")
let boolResults3 = engine.searchBoolean("\"exact phrase\" OR wildcard*")

# Fuzzy search with typo tolerance
let fuzzy = engine.searchFuzzy("programing", maxDistance = 2)

# Prefix and wildcard search
let prefix = engine.searchPrefix("prog", limit = 10)
let wildcard = engine.searchWildcard("prog*", limit = 10)
import barabadb/search/engine
import std/sets

# Index documents with facets
engine.indexDocument(
  docId = 1,
  text = "Nim tutorial",
  facets = {"category": @["programming", "tutorial"], "difficulty": @["beginner"]}.toTable
)

# Get facet counts
let counts = engine.getFacetCounts("category", limit = 10)
for count in counts:
  echo count.value, ": ", count.count

# Filter by facets
var filters = @[
  FacetFilter(field: "category", values: @["programming"], exclude: false),
  FacetFilter(field: "difficulty", values: @["advanced"], exclude: true)
]
let matchingDocs = engine.filterByFacets(filters)

# Aggregate multiple facets
let agg = engine.facets.aggregate(@["category", "difficulty"], matchingDocs)

Hybrid Search (Text + Vector)

import barabadb/search/engine
import barabadb/vector/engine

# Index vectors
engine.indexVector(1, @[0.1, 0.2, 0.3], {"title": "Doc 1"}.toTable)

# Hybrid search combining text and vector similarity
let hybrid = engine.hybridSearch(
  queryText = "programming",
  queryVec = @[0.1, 0.2, 0.3],
  k = 10,
  textWeight = 1.0,
  vecWeight = 1.0
)

# Filtered vector search
proc filterMeta(meta: Table[string, string]): bool =
  meta.getOrDefault("category") == "programming"

let filtered = engine.searchVectorFiltered(@[0.1, 0.2, 0.3], k = 10, filterMeta)

Configuration and Management

# Custom configuration
var config = defaultSearchConfig()
config.language = langBulgarian
config.maxSegmentSize = 100_000
config.ngramSize = 3
config.enableFacets = true

var engine = newUnifiedSearchEngine(config)

# Set field boosts for relevance tuning
engine.setFieldBoost("title", 2.0)
engine.setFieldBoost("body", 1.0)

# Change language
engine.setLanguage(langBulgarian)

# Compact segments for better performance
engine.compact()

# Get statistics
echo "Documents: ", engine.documentCount()
echo "Terms: ", engine.termCount()

# Remove documents
engine.removeDocument(1)