如何使用 elasticsearch nest api 创建自定义分析器以忽略重音和 pt-br 停用词?

Posted

技术标签:

【中文标题】如何使用 elasticsearch nest api 创建自定义分析器以忽略重音和 pt-br 停用词?【英文标题】:How to create a custom analyzer to ignore accents and pt-br stopwords using elasticsearch nest api? 【发布时间】:2020-06-23 21:11:01 【问题描述】:

首先,考虑到我正在使用一个“新闻”类(Noticia,葡萄牙语),它有一个名为“Content”的字符串字段(葡萄牙语中的 Conteudo)

public class Noticia

    public string Conteudo  get; set;  

我正在尝试创建一个索引,该索引被配置为忽略重音符号和 pt-br 停用词,并允许在高亮查询中分析多达 40mi 的字符。

我可以使用以下代码创建这样的索引:

var createIndexResponse = client.Indices.Create(indexName, c => c
    .Settings(s => s
        .Setting("highlight.max_analyzed_offset" , 40000000)
        .Analysis(analysis => analysis
            .TokenFilters(tokenfilters => tokenfilters
                .AsciiFolding("folding-accent", ft => ft
                )
                .Stop("stoping-br", st => st
                    .StopWords("_brazilian_")
                )
            )
            .Analyzers(analyzers => analyzers
                .Custom("folding-analyzer", cc => cc
                    .Tokenizer("standard")
                    .Filters("folding-accent", "stoping-br")
                )
            )
        )
    )
    .Map<Noticia>(mm => mm
        .AutoMap()
        .Properties(p => p
            .Text(t => t
                .Name(n => n.Conteudo)
                .Analyzer("folding-analyzer")
            )
        )
    )
);

如果我使用 Kibana 开发工具测试这个分析器,我会得到我想要的结果:没有重音和停用词被删除!

POST intranet/_analyze

  "analyzer": "folding-analyzer",
  "text": "Férias de todos os funcionários"

结果:


  "tokens" : [
    
      "token" : "Ferias",
      "start_offset" : 0,
      "end_offset" : 6,
      "type" : "<ALPHANUM>",
      "position" : 0
    ,
    
      "token" : "funcionarios",
      "start_offset" : 19,
      "end_offset" : 31,
      "type" : "<ALPHANUM>",
      "position" : 4
    
  ]

当我使用 NEST 使用折叠分析器分析查询时,返回相同(良好)的结果(返回标记“Ferias”和“funcionarios”)

var analyzeResponse = client.Indices.Analyze(a => a
.Index(indexName)
.Analyzer("folding-analyzer")
.Text("Férias de todos os funcionários")
);

但是,如果我使用 NEST ElasticSearch .NET 客户端执行搜索,则“Férias”(带重音)和“Ferias”(不带重音)之类的术语会被视为不同。

我的目标是执行一个返回所有结果的查询,无论单词是 Férias 还是 Ferias

这就是我用来查询elasticsearch的简化代码(C#嵌套):

var searchResponse = ElasticClient.Search<Noticia>(s => s
    .Index(indexName)
    .Query(q => q
    .MultiMatch(m => m
                .Fields(f => f
                    .Field(p => p.Titulo,4)
                    .Field(p => p.Conteudo,2)
                )
                .Query(termo)
            )
    )
);

这就是与 searchResponse 关联的扩展 API 调用

Successful (200) low level call on POST: /intranet/_search?pretty=true&error_trace=true&typed_keys=true
# Audit trail of this API call:
 - [1] HealthyResponse: Node: ###NODE ADDRESS### Took: 00:00:00.3880295
# Request:
"query":"multi_match":"fields":["categoria^1","titulo^4","ementa^3","conteudo^2","attachments.attachment.content^1"],"query":"Ferias","size":100
# Response:

  "took" : 0,
  "timed_out" : false,
  "_shards" : 
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  ,
  "hits" : 
    "total" : 
      "value" : 1,
      "relation" : "eq"
    ,
    "max_score" : 13.788051,
    "hits" : [
      
        "_index" : "intranet",
        "_type" : "_doc",
        "_id" : "4934",
        "_score" : 13.788051,
        "_source" : 
          "conteudo" : "blablabla ferias blablabla",
          "attachments" : [ ],
          "categoria" : "Novidades da Biblioteca - DBD",
          "publicadaEm" : "2008-10-14T00:00:00",
          "titulo" : "INFORMATIVO DE DIREITO ADMINISTRATIVO E LRF - JUL/2008",
          "ementa" : "blablabla",
          "matriculaAutor" : 900794,
          "atualizadaEm" : "2009-02-03T13:44:00",
          "id" : 4934,
          "indexacaoAtiva" : true,
          "status" : "Disponível"
        
      
    ]
  

我也尝试在查询中使用多字段和后缀,但没有成功

.Map<Noticia>(mm => mm
    .AutoMap()
    .Properties(p => p
        .Text(t => t
        .Name(n => n.Conteudo)
        .Analyzer("folding-analyzer")
        .Fields(f => f
            .Text(ss => ss
                .Name("folding")
                .Analyzer("folding-analyzer")
                )
        )

(...)

var searchResponse = ElasticClient.Search<Noticia>(s => s
    .Index(indexName)   
    .Query(q => q
    .MultiMatch(m => m
        .Fields(f => f
        .Field(p => p.Titulo,4)
        .Field(p => p.Conteudo.Suffix("folding"),2)       
                )
                .Query(termo)
            )
    )
);

任何线索我做错了什么或我可以做些什么来达到我的目标?

提前非常感谢!

【问题讨论】:

【参考方案1】:

几天后,我发现我做错了什么,这都是关于映射的。

这是我为解决问题而采取的步骤

1 - 首先我打开了 kibana 控制台,发现只有映射字段的最后一个字段被分配给我的自定义分析器(折叠分析器)

要测试每个字段,您可以使用 GET FIELD MAPPING API 和开发工具中的命令,如下所示:

GET /<index>/_mapping/field/<field>

然后您将能够查看您的分析仪是否被分配到您的领域

2 - 之后,我发现最后一个字段是唯一分配给我的自定义分析器的字段,原因是我在两个方面搞砸了流畅的映射:

首先,我必须正确链接我的文本属性 其次,我试图在另一个 Map 子句中映射另一个 POCO 类,而我应该使用 Object 子句

对我有用的正确映射有点像这样:

.Map<Noticia>(mm => mm
        .AutoMap()
        .Properties(p => p
            .Text(t => t
                .Name(n => n.Field1)
                .Analyzer("folding-analyzer")
            )
            .Text(t => t
                .Name(n => n.Field2)
                .Analyzer("folding-analyzer")
            )
            .Object<NoticiaArquivo>(o => o
                .Name(n => n.Arquivos)
                .Properties(eps => eps
                    .Text(s => s
                        .Name(e => e.NAField1)
                        .Analyzer("folding-analyzer")
                    )
                    .Text(s => s
                        .Name(e => e.NAField2)
                        .Analyzer("folding-analyzer")
                    )
                )
            )
        )
    )

最后,重要的是要分享一下,当您使用 .Analyzer("analiserName") 子句分配分析器时,您是在告诉弹性搜索您希望将参数分析器用于索引和搜索

如果您只想在搜索时而不是在索引时使用分析器,您应该使用 .SearchAnalyzer("analiserName") 子句。

【讨论】:

以上是关于如何使用 elasticsearch nest api 创建自定义分析器以忽略重音和 pt-br 停用词?的主要内容,如果未能解决你的问题,请参考以下文章

ElasticSearch(ES)使用Nested结构存储KV及聚合查询

使用 NEST 的 Elasticsearch:如何配置分析器来查找部分单词?

如何在 NEST2 中更新 Elasticsearch 文档

如何使用 NEST 更新 ElasticSearch 索引中的现有文档?

使用 C# 中的 NEST 库调用 elasticsearch 时,如何向 linq 语句添加条件逻辑?

如何使用NEST Bulk Api将文档添加到elasticsearch