【问题标题】:ElasticSearch / Nest search with synonyms, plural and mispellings使用同义词、复数和拼写错误进行 ElasticSearch / 嵌套搜索
【发布时间】:2017-06-08 19:06:11
【问题描述】:

我想做一个实现以下项目的搜索。

现在我已经通过正则表达式实现了所有这些,但它远未涵盖所有内容,我想知道我可以在多大程度上使用 ElasticSearch:

  • 同义词

    我的理解是这个是在创建索引的时候实现的。

    indexSettings.Analysis.TokenFilters.Add("synonym", new SynonymTokenFilter { Synonyms = new[] { "tire => tyre", "aluminum => aluminium" }, IgnoreCase = true, Tokenizer = "whitespace" }) ;

    但是我还需要包含复数吗?或者,

  • 单数词(shoes 和 shoe 应该是同一个匹配)

    这是否意味着我需要将“鞋子”放在同义词列表中?还是有其他方法?

  • 应该允许小的拼写错误、替换和遗漏

    这样 'automobile'、'automoble' 或 'automoblie' 会匹配。我不知道这是否可能。

  • 忽略所有停用词

    现在我正在通过正则表达式删除所有“the”、“this”、“my”等

我所有的搜索词都是简单的英文单词和数字;其他都不允许。

【问题讨论】:

    标签: elasticsearch nest


    【解决方案1】:

    这一切都可以通过 Elasticsearch 中的 configuring/writing a custom analyzer 实现。依次回答每个问题:

    同义词

    可以在索引时间、搜索时间或同时应用同义词。无论您选择哪种方法,都需要权衡取舍

    • 与在搜索时应用相比,在索引时应用同义词将导致更快的搜索,但代价是更多的磁盘空间、索引吞吐量以及添加/删除现有同义词的简便性和灵活性
    • 在搜索时应用同义词可以提高灵活性,但会降低搜索速度。

    还需要考虑同义词列表的大小以及更改频率(如果有的话)。我会考虑两种方法都尝试,然后决定哪种方法最适合您的场景和要求。

    单数词(shoes 和 shoe 应该是同一个匹配)

    您可以考虑使用stemming 将复数和单数单词简化为其根形式,使用基于算法或字典的词干分析器。也许从English Snowball stemmer 开始,看看它是如何为您工作的。

    您还应该考虑是否需要同时索引原始单词形式,例如精确词匹配在词根形式上的排名应该高于词干词吗?

    应该允许小的拼写错误、替换和遗漏

    考虑使用可利用fuzziness 处理拼写错误的查询。如果索引数据中存在拼写错误,请考虑在索引之前进行某种形式的清理。根据所有数据存储,Garbage In,Garbage Out :)

    忽略所有停用词

    使用English Stop token filter 删除停用词。

    将所有这些放在一起,一个示例分析器可能看起来像

    void Main()
    {
        var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
        var defaultIndex = "default-index";
        var connectionSettings = new ConnectionSettings(pool)
            .DefaultIndex(defaultIndex);
    
        var client = new ElasticClient(connectionSettings);
    
        if (client.IndexExists(defaultIndex).Exists)
            client.DeleteIndex(defaultIndex);
    
        client.CreateIndex(defaultIndex, c => c
            .Settings(s => s
                .Analysis(a => a
                    .TokenFilters(t => t
                        .Stop("my_stop", st => st
                            .StopWords("_english_", "i've")
                            .RemoveTrailing()
                        )
                        .Synonym("my_synonym", st => st
                            .Synonyms(
                                "dap, sneaker, pump, trainer",
                                "soccer => football"
                            )
                        )
                        .Snowball("my_snowball", st => st
                            .Language(SnowballLanguage.English)
                        )
                    )
                    .Analyzers(an => an
                        .Custom("my_analyzer", ca => ca
                            .Tokenizer("standard")
                            .Filters(
                                "lowercase",
                                "my_stop",
                                "my_snowball",
                                "my_synonym"
                            )
                        )
                    )
                )
            )
            .Mappings(m => m
                .Map<Message>(mm => mm
                    .Properties(p => p
                        .Text(t => t
                            .Name(n => n.Content)
                            .Analyzer("my_analyzer")
                        )
                    )
                )
            )
        );
    
        client.Analyze(a => a
            .Index(defaultIndex)
            .Field<Message>(f => f.Content)
            .Text("Loving those Billy! Them is the maddest soccer trainers I've ever seen!")
        );
    }
    
    public class Message
    {
        public string Content { get; set; }
    }
    

    my_analyzer 为上面生成以下标记

    {
      "tokens" : [
        {
          "token" : "love",
          "start_offset" : 0,
          "end_offset" : 6,
          "type" : "<ALPHANUM>",
          "position" : 0
        },
        {
          "token" : "those",
          "start_offset" : 7,
          "end_offset" : 12,
          "type" : "<ALPHANUM>",
          "position" : 1
        },
        {
          "token" : "billi",
          "start_offset" : 13,
          "end_offset" : 18,
          "type" : "<ALPHANUM>",
          "position" : 2
        },
        {
          "token" : "them",
          "start_offset" : 20,
          "end_offset" : 24,
          "type" : "<ALPHANUM>",
          "position" : 3
        },
        {
          "token" : "maddest",
          "start_offset" : 32,
          "end_offset" : 39,
          "type" : "<ALPHANUM>",
          "position" : 6
        },
        {
          "token" : "football",
          "start_offset" : 40,
          "end_offset" : 46,
          "type" : "SYNONYM",
          "position" : 7
        },
        {
          "token" : "trainer",
          "start_offset" : 47,
          "end_offset" : 55,
          "type" : "<ALPHANUM>",
          "position" : 8
        },
        {
          "token" : "dap",
          "start_offset" : 47,
          "end_offset" : 55,
          "type" : "SYNONYM",
          "position" : 8
        },
        {
          "token" : "sneaker",
          "start_offset" : 47,
          "end_offset" : 55,
          "type" : "SYNONYM",
          "position" : 8
        },
        {
          "token" : "pump",
          "start_offset" : 47,
          "end_offset" : 55,
          "type" : "SYNONYM",
          "position" : 8
        },
        {
          "token" : "ever",
          "start_offset" : 61,
          "end_offset" : 65,
          "type" : "<ALPHANUM>",
          "position" : 10
        },
        {
          "token" : "seen",
          "start_offset" : 66,
          "end_offset" : 70,
          "type" : "<ALPHANUM>",
          "position" : 11
        }
      ]
    }
    

    【讨论】:

    • 非常感谢拉斯,你不知道这有多大帮助! (我可能会带着相关问题回到这里:))
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-05
    • 2016-05-14
    • 2021-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多