测试分词器

753 发布于: 2021-05-14 读完约需 3 分钟

概述

在构建好自己的分词器时,测试分词器是否按照我们的期望执行是很有用的。这就是Analyze API发挥作用的地方。

测试内置分词器

为了开始使用Analyze API,我们可以进行测试,看看内置分词器如何分析一段文本

var analyzeResponse = client.Indices.Analyze(a => a
    .Analyzer("standard") // 使用内置的standard分词器
    .Text("F# is THE SUPERIOR language :)")
);

Elasticsearch将返回如下的分词结果:

{
  "tokens": [
    {
      "token": "f",
      "start_offset": 0,
      "end_offset": 1,
      "type": "<ALPHANUM>",
      "position": 0
    },
    {
      "token": "is",
      "start_offset": 3,
      "end_offset": 5,
      "type": "<ALPHANUM>",
      "position": 1
    },
    {
      "token": "the",
      "start_offset": 6,
      "end_offset": 9,
      "type": "<ALPHANUM>",
      "position": 2
    },
    {
      "token": "superior",
      "start_offset": 10,
      "end_offset": 18,
      "type": "<ALPHANUM>",
      "position": 3
    },
    {
      "token": "language",
      "start_offset": 19,
      "end_offset": 27,
      "type": "<ALPHANUM>",
      "position": 4
    }
  ]
}

它是由NEST反序列化AnalyzeResponse的一个实例,我们可以使用如下:

foreach (var analyzeToken in analyzeResponse.Tokens)
{
    Console.WriteLine($"{analyzeToken.Token}");
}

在使用内置的standard分词器进行测试时,我们注意到:

  • F#被标记为了f
  • 停用词isthe被包含了
  • “superior”也包括在内,但我们也想把”great”作为”superior”的同义词

接下来,我们将看看如何测试内置分词组件的组合,然后构建一个满足我们需求的分词器

测试内置分词组合

瞬态分词器可以由内置的分词组件组成,以测试分词配置

var analyzeResponse = client.Indices.Analyze(a => a
    .Tokenizer("standard")
    .Filter("lowercase", "stop")
    .Text("F# is THE SUPERIOR language :)")
);

Elasticsearch返回的测试分词结果为:

{
  "tokens": [
    {
      "token": "f",
      "start_offset": 0,
      "end_offset": 1,
      "type": "<ALPHANUM>",
      "position": 0
    },
    {
      "token": "superior",
      "start_offset": 10,
      "end_offset": 18,
      "type": "<ALPHANUM>",
      "position": 3
    },
    {
      "token": "language",
      "start_offset": 19,
      "end_offset": 27,
      "type": "<ALPHANUM>",
      "position": 4
    }
  ]
}

这时的分词结果删除了停词,但仍然将F#标记为“f”,而且没有”superior”的同义词”great”。

让我们构建一个带有附加组件的自定义分词器来解决这个问题。

测试自定义分词器

可以在索引中创建自定义分词器,既可以在创建索引时创建,也可以通过更新现有索引的设置来创建。

当添加到现有索引时,需要先关闭它。

在本例中,我们将向现有索引添加一个自定义分词器。首先,我们需要关闭索引。

client.Indices.Close("analysis-index");

现在,我们可以更新设置以添加分词器

client.Indices.UpdateSettings("analysis-index", i => i
    .IndexSettings(s => s
        .Analysis(a => a
            .CharFilters(cf => cf
                .Mapping("my_char_filter", m => m
                    .Mappings("F# => FSharp")
                )
            )
            .TokenFilters(tf => tf
                .Synonym("my_synonym", sf => sf
                    .Synonyms("superior, great")

                )
            )
            .Analyzers(an => an
                .Custom("my_analyzer", ca => ca
                    .Tokenizer("standard")
                    .CharFilters("my_char_filter")
                    .Filters("lowercase", "stop", "my_synonym")
                )
            )

        )
    )
);

然后再次打开索引。在这里,我们还要等待5秒钟,以使索引的状态变为绿色

client.Indices.Open("analysis-index");
client.Cluster.Health("analysis-index",h => h
    .WaitForStatus(WaitForStatus.Green)
    .Timeout(TimeSpan.FromSeconds(5))
);

索引打开并准备就绪后,让我们测试分词器

var analyzeResponse = client.Indices.Analyze(a => a
    .Index("analysis-index") 
    .Analyzer("my_analyzer")
    .Text("F# is THE SUPERIOR language :)")
);

Elasticsearch的分词测试结果为:

{
  "tokens": [
    {
      "token": "fsharp",
      "start_offset": 0,
      "end_offset": 2,
      "type": "<ALPHANUM>",
      "position": 0
    },
    {
      "token": "superior",
      "start_offset": 10,
      "end_offset": 18,
      "type": "<ALPHANUM>",
      "position": 3
    },
    {
      "token": "great",
      "start_offset": 10,
      "end_offset": 18,
      "type": "SYNONYM",
      "position": 3
    },
    {
      "token": "language",
      "start_offset": 19,
      "end_offset": 27,
      "type": "<ALPHANUM>",
      "position": 4
    }
  ]
}

从测试结果来看,已经得到了我们期望的分词结果。

测试字段的分词器

还可以为给定的字段类型映射测试分词器。给定一个用以下设置和映射创建的索引

client.Indices.Create("project-index", i => i
    .Settings(s => s
        .Analysis(a => a
            .CharFilters(cf => cf
                .Mapping("my_char_filter", m => m
                    .Mappings("F# => FSharp")
                )
            )
            .TokenFilters(tf => tf
                .Synonym("my_synonym", sf => sf
                    .Synonyms("superior, great")

                )
            )
            .Analyzers(an => an
                .Custom("my_analyzer", ca => ca
                    .Tokenizer("standard")
                    .CharFilters("my_char_filter")
                    .Filters("lowercase", "stop", "my_synonym")
                )
            )

        )
    )
    .Map<Project>(mm => mm
        .Properties(p => p
            .Text(t => t
                .Name(n => n.Name)
                .Analyzer("my_analyzer")
            )
        )
    )
);

名称字段上的分词器测试如下:

var analyzeResponse = client.Indices.Analyze(a => a
    .Index("project-index")
    .Field<Project, string>(f => f.Name)
    .Text("F# is THE SUPERIOR language :)")
);

版权声明:本作品系原创,版权归码友网所有,如未经许可,禁止任何形式转载,违者必究。

发表评论

登录用户才能发表评论, 请 登 录 或者 注册