Вот несколько указателей, которые помогут вам выбрать правильный путь
Фильтры символов
var ExpressionsList = new[]
{
"bad weather => storm",
"happy day => sun"
};
Подумайте, должны ли они быть фильтрами символов;они могут быть, но, как правило, символьные фильтры используются в местах, где токенизатор может некорректно токенизироваться, например,
- удаление тегов HTML перед токенизацией
- стандартный токенизатор, удаляющий
&
, когда мы в идеале хотелисохранить и заменить на and
в символьном фильтре - Стандартный токенизатор, токенизирующий
c#
как c
, когда в идеале мы хотели сохранить и заменить на csharp
в символьном фильтре
Возможно, вы хотите использовать символьный фильтр, но лучше использовать синонимы или график синонимов в случае нескольких слов.
Пользовательские анализаторы
The *Пользовательские анализаторы 1027 * и search
одинаковы, их можно удалить.Точно так же, если явно не установлено, search_analyzer
для поля типа данных text
будет настроено analyzer
, так что это немного упрощает.
Синонимы
var SynonymsList = new[]
{
"big => large, huge",
"small => tiny, minuscule",
"sun => sunshine, shiny, sunny"
};
Это направленная синонимная карта , то есть совпадения с левой стороны будут заменены всеми альтернативами с правой стороны.Если все должны рассматриваться как равные синонимы друг для друга, вам, скорее всего, не нужна карта направления, т.е.
var SynonymsList = new[]
{
"big, large, huge",
"small, tiny, minuscule",
"sun, sunshine, shiny, sunny"
};
. Это вернет все 3 документа для
var TestB1 = Client.Search<MyData>(S => S.Query(_ => _.QueryString(F => F.Query("stormy sunny")))).Documents;
// expected to return documents 1, 2, 3 because of synonyms: sun => sunny, shiny, sunshine
Фильтры токенов
.Custom("index", C => C
.CharFilters("expressions")
.Tokenizer("standard")
.Filters("synonyms", "standard", "lowercase", "stop")
)
.Custom("search", C => C
.CharFilters("expressions")
.Tokenizer("standard")
.Filters("synonyms", "standard", "lowercase", "stop")
)
Порядок фильтров токенов имеет значение, поэтому вы хотите запустить фильтр синонимов после фильтр нижнего регистра
Нечеткие запросы
Нечеткие запросы являются запросами уровня термина, поэтому входные данные запроса не подвергаются анализу, то есть, если вы запускаете его для поля, которое анализируется во время индекса, входные данные для нечеткого запросапотребуется сопоставить условия вывода для документа из анализа во время индекса.Скорее всего, это не даст правильных результатов, если входные данные запроса будут разбиты на несколько терминов во время индексации, то есть ввод нечеткого запроса будет рассматриваться как один полный термин, но значение времени индекса для поля целевого документа может иметьразделен на несколько терминов.
Взгляните на раздел Fuzziness из «Полного руководства» - он предназначен для Elasticsearch 2.x, но в значительной степени все еще актуален для более поздних версий.Вы, вероятно, захотите использовать полнотекстовый запрос, который поддерживает нечеткость и выполняет анализ во время запроса, например query_string
, match
или multi_match
запросов.
Пример
Размещение этихвместе, вот пример для работы при разработке
public class MyData
{
public string Id;
public string Title;
public string Tags;
}
public static void Main()
{
const string INDEX_NAME = "testindex";
var expressions = new[]
{
"bad weather => storm",
"happy day => sun"
};
var synonyms = new[]
{
"big, large, huge",
"small, tiny, minuscule",
"sun, sunshine, shiny, sunny"
};
// connect
var settings = new ConnectionSettings(new Uri("http://localhost:9200"))
.DefaultIndex(INDEX_NAME)
.DefaultFieldNameInferrer(s => s) // stop the camel case
.DefaultMappingFor<MyData>(m => m.IdProperty("Id"))
.DisableDirectStreaming()
.PrettyJson()
.OnRequestCompleted(callDetails =>
{
if (callDetails.RequestBodyInBytes != null)
{
Console.WriteLine(
$"{callDetails.HttpMethod} {callDetails.Uri} \n" +
$"{Encoding.UTF8.GetString(callDetails.RequestBodyInBytes)}");
}
else
{
Console.WriteLine($"{callDetails.HttpMethod} {callDetails.Uri}");
}
Console.WriteLine();
if (callDetails.ResponseBodyInBytes != null)
{
Console.WriteLine($"Status: {callDetails.HttpStatusCode}\n" +
$"{Encoding.UTF8.GetString(callDetails.ResponseBodyInBytes)}\n" +
$"{new string('-', 30)}\n");
}
else
{
Console.WriteLine($"Status: {callDetails.HttpStatusCode}\n" +
$"{new string('-', 30)}\n");
}
});
var Client = new ElasticClient(settings);
// erase the old index, if any
if (Client.IndexExists(INDEX_NAME).Exists) Client.DeleteIndex(INDEX_NAME);
// create the index
var createIndexResponse = Client.CreateIndex(INDEX_NAME, c => c
.Settings(s => s
.Analysis(a => a
.CharFilters(cf => cf
.Mapping("expressions", E => E
.Mappings(expressions)
)
)
.TokenFilters(tf => tf
.Synonym("synonyms", sy => sy
.Synonyms(synonyms)
.Tokenizer("whitespace")
)
)
.Analyzers(an => an
.Custom("index", ca => ca
.CharFilters("expressions")
.Tokenizer("standard")
.Filters("standard", "lowercase", "synonyms", "stop")
)
)
)
)
.Mappings(m => m
.Map<MyData>(mm => mm
.AutoMap()
.Properties(p => p
.Text(t => t
.Name(n => n.Title)
.Analyzer("index")
)
.Text(t => t
.Name(n => n.Tags)
.Analyzer("index")
)
)
)
)
);
// add some data
var data = new List<MyData>
{
new MyData { Id = "1", Title = "nice stormy weather", Tags = "storm nice" },
new MyData { Id = "2", Title = "a large storm with sunshine", Tags = "storm large sunshine" },
new MyData { Id = "3", Title = "a storm during a sunny day", Tags = "sun storm" }
};
Client.IndexMany(data);
Client.Refresh(INDEX_NAME);
//var query = "stormy sunny";
var query = "stromy sunny";
// var query = "bad weather";
// var query = "a large happy day";
var testA1 = Client.Search<MyData>(s => s
.Query(q => q
.MultiMatch(fu => fu
.Fields(f => f
.Field(ff => ff.Tags)
.Field(ff => ff.Title)
)
.Query(query)
.Fuzziness(Fuzziness.EditDistance(2))
)
)
).Documents;
}
Я добавил .DisableDirectStreaming()
, .PrettyJson()
и обработчик .OnRequestCompleted(...)
в настройки соединения, чтобы вы могли видеть запросы и ответы, записанные вконсоль.Они полезны при разработке, но вы, вероятно, захотите удалить их для производства, поскольку они увеличивают накладные расходы.Небольшое приложение, такое как Linqpad, поможет при разработке здесь:)
В этом примере используется запрос multi_match
с нечеткостью, включенной с расстоянием редактирования 2 (здесь может потребоваться просто использовать автоматическую нечеткость, она делает разумную работу), работает в полях Tags
и Title
.Все три документа возвращаются по запросу (опечатка) "stromy sunny"