小编典典

如何使用Nest C#Client在Elasticsearch中进行重音不敏感搜索?

elasticsearch

我是Elasticsearch新手。

可以说我们有一个这样的类:

public class A
{
    public string name;
}

我们有2个文档,其名称分别为 “Ayşe”“ Ayse”

现在, 我希望能够存储带有重音符号的名称,但是当我搜索时希望能够将不重音符号查询的结果作为重音敏感结果

例如:当我搜索 “ Ayse”“Ayşe”时 ,它应同时返回存储的 “Ayşe”和“ Ayse” (带有重音符号)。

现在,当我搜索“ Ayse”时,它仅返回“ Ayse”,但我也希望得到“Ayşe”。

当我查看Elasticsearch文档时,我发现需要使用折叠属性来实现这一点。但是我不明白如何使用Nest属性/函数。

顺便说一句,我现在正在使用自动映射来创建映射,如果可能的话,我希望能够继续使用它。

我正在寻找为期2天的答案,目前还无法解决。

需要什么/在哪里进行更改?可以给我提供代码示例吗?

谢谢。

编辑1:

我想出了如何使用分析器来创建属性的子字段并通过针对子字段的基于术语的查询来获得结果。

现在,我知道我可以进行多字段搜索,但是 有没有办法在全文搜索中包含子字段?

谢谢。


阅读 286

收藏
2020-06-22

共1个答案

小编典典

您可以配置分析器以在索引时对文本进行分析,将其索引到要在查询时使用的multi_field中,以及保留原始源以返回结果。根据您所遇到的问题,听起来像您想要一个自定义分析器,该分析器使用asciifolding令牌过滤器在索引和搜索时转换为ASCII字符。

鉴于以下文件

public class Document
{
    public int Id { get; set;}
    public string Name { get; set; }
}

创建索引时可以完成自定义分析器的设置。我们也可以同时指定映射

client.CreateIndex(documentsIndex, ci => ci
    .Settings(s => s
        .NumberOfShards(1)
        .NumberOfReplicas(0)
        .Analysis(analysis => analysis
            .TokenFilters(tokenfilters => tokenfilters
                .AsciiFolding("folding-preserve", ft => ft
                    .PreserveOriginal()
                )
            )
            .Analyzers(analyzers => analyzers
                .Custom("folding-analyzer", c => c
                    .Tokenizer("standard")
                    .Filters("standard", "folding-preserve")
                )
            )
        )
    )
    .Mappings(m => m
        .Map<Document>(mm => mm
            .AutoMap()
            .Properties(p => p
                .String(s => s
                    .Name(n => n.Name)
                    .Fields(f => f
                        .String(ss => ss
                            .Name("folding")
                            .Analyzer("folding-analyzer")
                        )
                    )
                    .NotAnalyzed()
                )
            )
        )
    )
);

在这里,我创建了一个只有一个分片且没有副本的索引(您可能希望针对您的环境进行更改),并创建了一个自定义分析器,folding- analyzer该分析器将标准令牌生成standard器与folding-preserve令牌过滤器和执行ascii
的令牌过滤器结合使用折叠,除了折叠的令牌外,还存储原始令牌(更多有关为什么可能在一分钟内有用的信息)。

我还映射了Document类型,将Name属性映射为multi_field,具有默认字段not_analyzed(用于聚合)和将使用进行分析的.folding
子字段folding-analyzer。默认情况下,原始源文档也将由Elasticsearch存储。

现在让我们索引一些文档

client.Index<Document>(new Document { Id = 1, Name = "Ayse" });
client.Index<Document>(new Document { Id = 2, Name = "Ayşe" });

// refresh the index after indexing to ensure the documents just indexed are
// available to be searched
client.Refresh(documentsIndex);

最后,搜索 Ayşe

var response = client.Search<Document>(s => s
    .Query(q => q
        .QueryString(qs => qs
            .Fields(f => f
                .Field(c => c.Name.Suffix("folding"))
            )
            .Query("Ayşe")
        )
    )
);

产量

{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "failed" : 0
  },
  "hits" : {
    "total" : 2,
    "max_score" : 1.163388,
    "hits" : [ {
      "_index" : "documents",
      "_type" : "document",
      "_id" : "2",
      "_score" : 1.163388,
      "_source" : {
        "id" : 2,
        "name" : "Ayşe"
      }
    }, {
      "_index" : "documents",
      "_type" : "document",
      "_id" : "1",
      "_score" : 0.3038296,
      "_source" : {
        "id" : 1,
        "name" : "Ayse"
      }
    } ]
  }
}

这里要强调的两件事:

首先,_source包含发送到Elasticsearch的原始文本,因此使用response.Documents,您将获得原始名称,例如

string.Join(",", response.Documents.Select(d => d.Name));

会给你“Ayşe,Ayse”

其次,还记得我们将原始令牌保留在asiifolding令牌过滤器中吗?这样做意味着我们可以执行经过分析的查询,以不敏感地匹配重音,但在计分时也要考虑重音;在上面的例子中,得分
艾谢费里德阿卡尔 匹配 艾谢费里德阿卡尔 比更高 艾谢费里德阿卡尔 匹配 艾谢费里德阿卡尔 因为令牌 艾谢费里德阿卡尔
艾谢费里德阿卡尔 被索引为前,而仅 艾谢费里德阿卡尔
被索引为后者。当针对该Name属性执行要进行分析的查询时,将使用对该查询进行分析并执行对folding-analyzer匹配项的搜索

Index time
----------

document 1 name: Ayse --analysis--> Ayse

document 2 name: Ayşe --analysis--> Ayşe, Ayse


Query time
-----------

query_string query input: Ayşe --analysis--> Ayşe, Ayse

search for documents with tokens for name field matching Ayşe or Ayse
2020-06-22