Files
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

12 KiB
Raw Permalink Blame History

Унифициран модул за търсене

Преглед

UnifiedSearchEngine е основната входна точка за всички операции по търсене в BarabaDB. Той обединява множество възможности за търсене в единен, свързан API:

  • Пълнотекстово търсене (FTS) — извличане с BM25 класиране върху сегментирани обърнати индекси.
  • Векторно търсене — приблизително търсене на най-близки съседи чрез HNSW с опционално филтриране по метаданни.
  • Фразово търсене — точно или slop-толерантно съвпадение на фрази.
  • Булеви заявки — пълна булева алгебра с AND, OR, NOT, групиране, диапазони, wildcards, fuzzy и proximity оператори.
  • Фасетно търсене — категорично филтриране с бройки по стойности за всяко поле.
  • Нечетко търсене (Fuzzy) — генериране на кандидати чрез N-грами, проверени с Levenshtein разстояние.
  • Хибридно търсене — комбинира FTS и векторни резултати за смесено извличане.

Инсталация

Добавете модула към вашия Nim проект:

import barabadb/search/engine

Не са необходими допълнителни зависимости; модулът за търсене е част от основния пакет barabadb.

Основна употреба

import barabadb/search/engine

let config = defaultSearchConfig()
var search = newUnifiedSearchEngine(config)

# Index documents
search.indexDocument(1, "The quick brown fox", {"title": "Animals"}.toTable)
search.indexDocument(2, "Lazy dog sleeps all day", {"title": "Pets"}.toTable)

# BM25 search
let results = search.search("quick fox", limit = 10)

# Phrase search
let phrases = search.searchPhrase(@["quick", "brown"], slop = 0)

# Boolean query
let boolResults = search.searchBoolean("quick AND (fox OR dog)")

# Fuzzy search
let fuzzy = search.searchFuzzy("quik", maxDistance = 2)

# Prefix search
let prefix = search.searchPrefix("quic*")

# Vector search
search.indexVector(1, @[0.1'f32, 0.2, 0.3], {"category": "A"}.toTable)
let vecResults = search.searchVector(@[0.15'f32, 0.25, 0.35], k = 10)

# Hybrid search (combines FTS + vector)
let hybrid = search.hybridSearch("fox", @[0.1'f32, 0.2, 0.3], k = 10)

Разширени възможности

Фасетно търсене

Фасетното търсене позволява филтриране на резултатите по категорични метаданни и извличане на агрегирани бройки по стойност на всеки фасет.

# Index with facets
search.indexDocument(1, "Nim programming book",
  fields = {"author": "John"}.toTable,
  facets = {"category": @["programming", "books"], "language": @["nim"]}.toTable)

# Filter by facets
let filters = @[FacetFilter(field: "category", values: @["programming"])]
let filteredDocs = search.filterByFacets(filters)

# Get facet counts
let counts = search.getFacetCounts("category")

Усилване на полета

Усилването на полета настройва относителната важност на съвпаденията в различните полета. По-висок множител означава, че съвпаденията в това поле допринасят повече за крайния резултат.

search.setFieldBoost("title", 3.0)  # Title matches 3x more important
search.setFieldBoost("author", 2.0)

Поддръжка на множество езици

Модулът за търсене включва Porter2 stemmer-и за няколко езика. Сменете активния stemmer, за да съответства на езика на вашите документи и да подобрите recall-а.

search.setLanguage(langBulgarian)  # Switch to Bulgarian stemmer

Поддържани stemmer-и: английски (langEnglish), български (langBulgarian), немски (langGerman), френски (langFrench), руски (langRussian).

Управление на сегменти

Индексът е организиран в сегменти, които периодично се сливат. Компактизирането намалява броя на сегментите и подобрява производителността на търсенето.

# Compact segments for better performance
search.compact()

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

Синтаксис на булевите заявки

Парсерът за булеви заявки поддържа богат синтаксис за съставяне на сложни изрази за търсене.

Оператор Пример Описание
AND (по подразбиране) quick brown И двата термина са задължителни
AND (изричен) quick AND brown И двата термина са задължителни
OR quick OR brown Който и да е от термините
NOT quick NOT brown Изключва brown
Фраза "quick brown fox" Точна фраза
Близост "quick fox"~3 В рамките на 3 думи
Wildcard quic* Съвпадение по префикс
Нечетко quik~2 Максимум 2 редакции
Групиране (quick OR slow) AND fox Булеви групи
Диапазон price:[10 TO 100] Числов диапазон

Примери

# Simple conjunction — both terms must appear
let r1 = search.searchBoolean("database indexing")

# Disjunction with exclusion
let r2 = search.searchBoolean("search OR retrieval NOT deprecated")

# Phrase with proximity
let r3 = search.searchBoolean("\"quick fox\"~5")

# Grouped boolean with field range
let r4 = search.searchBoolean("(nim OR rust) AND performance score:[80 TO 100]")

Характеристики на производителността

HNSW векторно търсене

Векторният индекс използва Hierarchical Navigable Small World граф с heap-based searchLayer:

  • Скорост: 2.4 пъти по-бързо от линейно сканиране при heap-оптимизирания път.
  • Recall@10: 92–99% в зависимост от размера на набора от данни и размерността.
  • Филтрирано търсене: Използва итеративно задълбочаване вместо фиксиран 10x ef множител, така че заявките с филтриране по метаданни остават ефективни без жертване на recall-а.

Сегментно индексиране

Документите се индексират в непроменяеми сегменти, които се сливат при компактизиране:

  • Автоматично сегментиране: Нов сегмент се създава на всеки 50 000 документа.
  • Софт-изтриване: Премахнатите документи се маркират мигновено и се изключват от резултатите; физическото премахване става при компактизиране.
  • Периодично компактизиране: search.compact() слива активните сегменти, възстановява пространство от софт-изтрити документи и намалява броя на сегментите, сканирани при всяка заявка.

Нечетко търсене с N-грами

Нечеткото съвпадение е двуетапен процес:

  1. Генериране на кандидати: Обърнат индекс от триграми осигурява O(1) достъп до термини, споделящи поне една триграма със заявката.
  2. Филтриране по сходство: Кандидатите първо се оценяват по Jaccard сходство върху множествата от триграми (евтино), след което се проверяват с точно Levenshtein разстояние (скъпо, но приложено само върху краткия списък с кандидати).

Архитектура

UnifiedSearchEngine
├── SegmentIndex (FTS with BM25)
│   └── Multiple segments (auto-merge)
├── NGramIndex (fuzzy/prefix/wildcard)
│   └── Trigram inverted index
├── FacetIndex (categorical filtering)
│   └── Per-field value → docId mapping
├── HNSWIndex (vector search)
│   └── Heap-optimized searchLayer
└── Porter2 Stemmers (EN/BG/DE/FR/RU)

Всеки подиндекс е независимо тестваем и може да се използва изолирано, ако е необходимо само подмножество от възможностите за търсене.

Миграция от FTS Engine

Ако надграждате от самостоятелния FTS engine, миграцията е проста.

Стар код:

import barabadb/fts/engine
var idx = newInvertedIndex()
idx.addDocument(1, "text")
let results = idx.search("query")

Нов код:

import barabadb/search/engine
var search = newUnifiedSearchEngine()
search.indexDocument(1, "text")
let results = search.search("query")

Ключови промени:

Стар API Нов API Бележки
newInvertedIndex() newUnifiedSearchEngine() Включва всички подиндекси
addDocument(id, text) indexDocument(id, text, fields, facets) Полетата и фасетите са опционални
search(query) search(query, limit) Добавен е параметър за лимит

Старият модул barabadb/fts/engine е deprecated и ще бъде премахнат в бъдеща версия.

Резултати от бенчмаркове

Бенчмарковете са изпълнени на една нишка, 128-мерни вектори, HNSW параметри M=16, efConstruction=200, efSearch=50.

N=1K:   insert=0.24s  search=0.30ms  recall@10=99.6%
N=5K:   insert=2.64s  search=0.94ms  recall@10=97.8%
N=10K:  insert=6.94s  search=1.09ms  recall@10=92.6%
N=50K:  insert=70.67s search=2.26ms  recall@10=75.5%
  • insert — общо wall-clock време за индексиране на N документа (включително вмъкване на вектори).
  • search — средна латентност на хибридна заявка за търсене.
  • recall@10 — дял на истинските топ-10 най-близки съседи, намерени от HNSW, измерен спрямо brute-force ground truth.