提到 Easysearch(或 Elasticsearch)的 分词器(Analyzer),很多开发者的第一反应是:“我就用默认的 standard,或者装个 ik_max_word,够用就行。”
但当你遇到下面这些场景时,标准分词器往往会让你抓狂:
- 用户搜邮箱
john.doe@example.com,搜john能出,搜gmail却出不来? - 搜商品型号
X-2000-Pro,搜X2000居然搜不到? - 想让搜索忽略大小写,但又不想忽略某些特定的专有名词?
这时候,你需要的不是寻找更强大的插件,而是自己动手组装一个 Analyzer。
别被“自定义”这三个字吓倒。在 Easysearch 中,自定义分词器就像搭乐高积木一样简单且有趣。
分词器的“乐高”结构 #
一个完整的 Analyzer 由三个核心组件按顺序流水线组成。我们可以把它们想象成三个不同的积木桶,你可以从每个桶里挑出你需要的积木,拼成一个专属的分词器。
- 字符过滤器(Character Filters) —— 预处理
- 作用:在分词前对原始字符串进行增删改。
- 常见积木:
html_strip(去 HTML 标签)、mapping(字符替换,如把&换成and)。 - 数量:0 个或多个。
- 分词器(Tokenizer) —— 切分
- 作用:把字符串切成一个个的 Token(词)。
- 常见积木:
whitespace(按空格切)、standard(按语法切)、pattern(按正则切)。 - 数量:必须且只能有 1 个。
- Token 过滤器(Token Filters) —— 加工
- 作用:对切好的 Token 进行处理(转小写、去停用词、加同义词)。
- 常见积木:
lowercase、stop、synonym、unique。 - 数量:0 个或多个。
实战:打造一个“商品型号”专用分词器 #
假设我们电商网站有一批商品,型号格式如 CODE-2024-PRO。
需求:
- 忽略大小写(搜
code能出)。 - 支持部分匹配(搜
2024能出)。 - 支持兼容匹配(搜
CODE2024也能出)。
如果用默认的 standard,它会把 CODE-2024-PRO 切分成 [code, 2024, pro]。但这满足不了“兼容匹配”的需求(搜 CODE2024 没法匹配到单独的词)。
我们来 DIY 一个。
第一步:设计蓝图 #
- Tokenizer: 使用
pattern分词器。我们可以定义一个正则,把非字母数字的字符(如-)作为分隔符,或者反过来,只保留字母数字。 - Token Filter:
lowercase:统一转小写。ngram(可选):如果我们想支持极强的模糊搜索。
但为了解决 CODE2024 这种连写搜 CODE-2024 的问题,我们换个思路:保留原始符号,同时生成不带符号的版本。或者更简单,在索引时就把标点符号去掉。
让我们尝试一个更通用的配置:Mapping Char Filter + Whitespace Tokenizer。
第二步:编写 DSL #
我们在创建索引(Index)时,通过 settings 来定义这个 Analyzer。
PUT /product_index
{
"settings": {
"analysis": {
"char_filter": {
"my_hyphen_remover": {
"type": "pattern_replace",
"pattern": "-",
"replacement": ""
}
},
"analyzer": {
"my_product_analyzer": {
"type": "custom",
"char_filter": [
"html_strip", // 1. 先去 HTML
"my_hyphen_remover" // 2. 把横杠去掉 (CODE-2024 -> CODE2024)
],
"tokenizer": "standard", // 3. 标准切分
"filter": [
"lowercase" // 4. 转小写
]
}
}
}
},
"mappings": {
"properties": {
"product_code": {
"type": "text",
"analyzer": "my_product_analyzer"
}
}
}
}
注意:上面的配置是一个激进的例子。它会把 CODE-2024 变成 code2024。这样用户搜 code2024 完美匹配。但搜 2024 可能就挂了。
更优的方案:保留分隔符,但支持多种切分
通常我们会定义一个 Analyzer,只负责简单的切分和归一化:
PUT /product_index_v2
{
"settings": {
"analysis": {
"analyzer": {
"code_analyzer": {
"type": "custom",
"tokenizer": "whitespace", // 按空格切,保留 CODE-2024-PRO 作为一个整体(假设没空格)
"filter": [
"lowercase", // 转小写
"word_delimiter_graph" // 神器!智能拆分单词
]
}
}
}
}
}
这里用到了 word_delimiter_graph,它是处理结构化文本(如 ID、型号、MAC 地址)的神器。它能配置成:
- 把
WiFi拆成Wi,Fi。 - 把
CODE-2024拆成CODE,2024。 - 甚至保留原始词
CODE-2024。
调试:不确定的事,测一下 #
配置好了不敢用?Easysearch 提供了 _analyze API,让你在写入数据前就能看到效果。
POST /product_index_v2/_analyze
{
"analyzer": "code_analyzer",
"text": "CODE-2024-PRO"
}
观察返回的 Token 列表,看看是否包含了你期望的所有搜索词。
总结 #
自定义 Analyzer 并不是黑魔法,它只是对 Easysearch 现有能力的重新排列组合。
- 不要迷信默认配置:默认配置是为了通用性,而你的业务往往有特殊性。
- **善用 **
_analyze:所见即所得,调试是自定义分词器的核心步骤。 - 从需求倒推:先想好用户会怎么搜(搜
2024还是code),再决定怎么切。
当你开始尝试自定义 Analyzer 时,你就已经从一个 Easysearch 的“使用者”进阶为了“掌控者”。





