在我之前的文章 “Elasticsearch:词分析中的 Normalizer 的使用”, 我对 analyzer 中的 normalizer 有一个简单的介绍。今天我将展示使用 normalizer 如何解决问题并降低解决方案的复杂性。
Normalizer 是一种只会为给定输入生成一个 token 的功能。 也就是说,如果你的输入是 “This text is 1 token”,则生成的唯一标记将是 “This text is 1 token”。
然而 Normalizer 有一些限制,比如 Filters,你可以在这里看到适用的过滤器列表。
问题
在这个问题中,我们有一个车辆登记索引,其中一个登记信息是车牌。 车牌有一个标准:3 个字母和 4 个数字,我举一些例子:MTB7465,或 MMO9689。
最初,该索引将车牌索引为 keyword,因此无法通过车牌前缀,比如 MTB ,来进行搜索。
我们可以使用 Normalizer 来解决这个问题。
我们可以做两个更改:
- 第一个是创建一个 normalizer,它将生成一个 token,但仅使用车牌的文本部分(MTB7412 -> MTB),这样我就可以通过前缀进行搜索。 你可以看到我使用了 pattern-replace 来从车牌中删除数字部分。
- 第二部分是创建一个名为 prefix 的字段,它将接收车牌前缀,这是一个 keyword 的字段。
映射/设置如下所示:
`
1. PUT carplates
2. {
3. "settings": {
4. "analysis": {
5. "normalizer": {
6. "default_normalizer": {
7. "type": "custom",
8. "char_filter": [
9. "prefix_plate_char_filter"
10. ],
11. "filter": ["lowercase"]
12. }
13. },
14. "char_filter": {
15. "prefix_plate_char_filter": {
16. "type": "pattern_replace",
17. "pattern": """\d+""",
18. "replacement": ""
19. }
20. }
21. }
22. },
23. "mappings": {
24. "properties": {
25. "license_plate": {
26. "type": "keyword",
27. "fields": {
28. "prefix": {
29. "type": "keyword",
30. "normalizer": "default_normalizer"
31. }
32. }
33. }
34. }
35. }
36. }
`
在索引一些车辆后,我们可以执行测试。比如我们创建如下的文档:
1. PUT carplates/_doc/1
2. {
3. "license_plate": "MTB7465"
4. }
6. PUT carplates/_doc/2
7. {
8. "license_plate": "MMO9689"
9. }
执行下面的搜索我们不会得到结果,因为我们只搜索许可证位置的一部分。
1. GET carplates/_search
2. {
3. "query": {
4. "term": {
5. "license_plate": "mtb"
6. }
7. }
8. }
现在,如果我们使用我们的 prefix 字段,我们将得到结果。
1. GET carplates/_search
2. {
3. "query": {
4. "term": {
5. "license_plate.prefix": "mtb"
6. }
7. }
8. }
上述搜索结果为:
1. {
2. "took": 4,
3. "timed_out": false,
4. "_shards": {
5. "total": 1,
6. "successful": 1,
7. "skipped": 0,
8. "failed": 0
9. },
10. "hits": {
11. "total": {
12. "value": 1,
13. "relation": "eq"
14. },
15. "max_score": 0.6931471,
16. "hits": [
17. {
18. "_index": "carplates",
19. "_id": "1",
20. "_score": 0.6931471,
21. "_source": {
22. "license_plate": "MTB7465"
23. }
24. }
25. ]
26. }
27. }
也许您会想到其他方法来获得相同的结果,但我相信使用 Normalizer 非常实用并且比其他方法更简单,因为你不需要更改字段类型或使用解析器。