Сделать Elasticsearch диакритические знаки нечувствительными - PullRequest
0 голосов
/ 25 сентября 2019

Я использую Elasticsearch 6.6.0 и NEST в проекте .NET MVC.

Я индексирую некоторые продукты, используя этот код:

var esSettings = new ConnectionSettings(node);
esSettings = esSettings.DefaultIndex(IndexInstanceName);
esSettings = esSettings
    .DefaultMappingFor<SearchableProduct>(s => s.IdProperty("Id").IndexName(IndexInstanceName + "-products-" + ConfigurationManager.AppSettings["DefaultCulture"]));

var elastic = new ElasticClient(esSettings);
var mapResponse = elastic.Map<SearchableProduct>(x => x.AutoMap().Index(IndexInstanceName + "-products-" + culture));

var indexState = new IndexState
{
    Settings = new IndexSettings()
};

indexState.Settings.Analysis = new Analysis
{
    Analyzers = new Analyzers()
};

indexState.Settings.Analysis.Analyzers.Add("nospecialchars", new CustomAnalyzer
{
    Tokenizer = "standard",
    Filter = new List<string> { "standard", "lowercase", "stop", "asciifolding" }
});

//products
if (!elastic.IndexExists(IndexInstanceName + "-products-" + culture).Exists)
{
    var response = elastic.CreateIndex(
        IndexInstanceName + "-products-" + culture,
        s => s.InitializeUsing(indexState)
               .Mappings(m => m.Map<SearchableProduct>(sc => sc.AutoMap())));
}

await this.IndexProductsAsync(context, products, elastic, culture);
await elastic.RefreshAsync(new RefreshRequest(IndexInstanceName + "-products-" + culture));

, а для поиска я используюкод ниже:

ISearchResponse<SearchableProduct> result = await elastic.SearchAsync<SearchableProduct>(s => s
                           .Index(elasticIndexName + "-products-" + culture)
                           .Take(DefaultPageSize)
                           .Source(src => src.IncludeAll())
                            .Query(query =>
                               query.QueryString(qs =>
                                qs.Query(q).DefaultOperator(Operator.And).Fuzziness(Fuzziness.EditDistance(0)).Fields(x => x.Field(d => d.Name, 2)
                                                    .Field(d => d.MetaTitle, 1)
                                                    .Field(d => d.Image, 1)
                                                    .Field(d => d.SystemId, 2)
                                                    .Field(d => d.Manufacturer, 1)
                                        )
                            ))
                           .Sort(d => d.Ascending(SortSpecialField.Score))
                        );

Когда я ищу слово с ударением на греческом языке (например, παγωτό), я получаю результаты (потому что в моем индексе товар индексируется с ударением), но когда я использую то же слово безакцент (например, παγωτο) я не получаю результатов.

Что-то не так с настройками индексации или кодом поиска?

Могу ли я индексировать свои данные без акцентов или альтернативно индексировать их как есть, но сделать поиск или индексировать акцент нечувствительным?

1 Ответ

1 голос
/ 26 сентября 2019

Создание поля с помощью анализатора greek обеспечит, чтобы индексированный текст и строка запроса проходили один и тот же путь анализа.Для παγωτό это означает, что во время индексирования текст будет разбит на токены παγωτ, а также во время выполнения запроса.

Пожалуйста, проверьте мой пример, который создает поле с greek анализатором, и примервыводит оба документа с παγωτό и παγωτο при поиске παγωτό или παγωτο.

class Program
{
    static async Task Main(string[] args)
    {
        var connectionPool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
        var settings = new ConnectionSettings(connectionPool)
            .DefaultIndex("index_name")
            .DisableDirectStreaming()
            .PrettyJson();
        var client = new ElasticClient(settings);

        await client.Indices.DeleteAsync("index_name");

        var createIndexResponse = await client.Indices.CreateAsync("index_name",
            c => c
                .Map(map => map.AutoMap<Document>()));

        await client.IndexManyAsync(new []
            {new Document {Id = 1, Text = "παγωτό"}, new Document {Id = 2, Text = "παγωτο"},});

        await client.Indices.RefreshAsync();

        var query = "παγωτό";
        var searchResponse = await client.SearchAsync<Document>(s => s
            .Query(q => q.Match(m => m.Field(f => f.Text).Query(query))));

        Console.OutputEncoding = Encoding.UTF8;

        Print(query, searchResponse);

        query = "παγωτο";
        var searchResponse2 = await client.SearchAsync<Document>(s => s
            .Query(q => q.Match(m => m.Field(f => f.Text).Query(query))));

        Print(query, searchResponse2);
    }

    private static void Print(string query, ISearchResponse<Document> searchResponse)
    {
        Console.WriteLine($"For {query} found:");
        foreach (var document in searchResponse.Documents)
        {
            Console.WriteLine($"Document {document.Id} {document.Text}");
        }
    }
}

public class Document
{
    public int Id { get; set; }
    [Text(Analyzer = "greek")]
    public string Text { get; set; }
}

Печать:

For παγωτό found:
Document 1 παγωτό
Document 2 παγωτο
For παγωτο found:
Document 1 παγωτό
Document 2 παγωτο

Надеюсь, что поможет.

...