Допустим, есть таблица с двумя полями:
id
и
data
. В поле
data
хранится произвольный текст на русском языке, в котором могут быть имена и фамилии. Нужно реализовать поиск по этой таблице:
Требования к поиску:
- Независимость от падежа ("иванова" совпадает с "иванов", "ивановых", "ивановичев")
- Толерантность к опечаткам ("сименов" совпадает с "семёнов")
- Ранжирование по релевантности
Попробовал полнотекстовый поиск PostgreSQL с пакетом
pg_tgrm
, как надо не работает:
SELECT to_tsvector('russian', 'Анна Иванова') @@ to_tsquery('russian', 'иванов') -- false
SELECT to_tsvector('russian', 'Иван Иванов') @@ to_tsquery('russian', 'иванова') -- false
SELECT similarity('иванов', 'иванова') -- 0.66
SELECT similarity('иванов', 'ивановым') -- 0.6
SELECT similarity('иваныч', 'иванович') -- 0.33
Аналогично, ElasticSearch тоже ничего не находит:
client.CreateIndex(
index,
m => m.Mappings(mp =>
mp.Map<Page>(mx =>
mx.Properties(p =>
p.Text(x =>
x.Name(f => f.Title)
.Analyzer("index_ru")
.SearchAnalyzer("search_ru")
)
)
)
)
.Settings(s =>
s.Analysis(a =>
a.CharFilters(c =>
c.Mapping("filter_ru_e", z => z.Mappings("Ё => Е", "ё => е"))
)
.Tokenizers(t =>
t.NGram("n_gram", ng =>
ng.MinGram(4).MaxGram(20)
)
)
.Analyzers(an =>
an.Custom("index_ru", ac =>
ac.CharFilters("html_strip", "filter_ru_e")
.Tokenizer("n_gram")
.Filters("stop", "lowercase", "russian_morphology", "english_morphology")
)
.Custom("search_ru", ac =>
ac.CharFilters("html_strip", "filter_ru_e")
.Tokenizer("standard")
.Filters("stop", "lowercase", "russian_morphology", "english_morphology")
)
)
)
)
);
var docs = new []
{
new Page("Иван Иванов"),
new Page("Петр Иванов"),
new Page("Илья Иванов"),
new Page("Светлана Иванова"),
new Page("Анна Иванова"),
};
foreach(var doc in docs)
client.Index(doc);
var query = client.Search<Page>(
s => s.Query(
q => q.Match(
f => f.Field(x => x.Title)
.Query("иванов")
)
)
);
Неужели нет готового инструмента, который работает как следует?