TL;DR
从版本 23.0.0 开始,Manticore 可以通过
bigram_delimiter
和数字感知的
bigram_index
模式,使搜索如 xt850 匹配 xt 850。
这解决了产品搜索中常见的分词不匹配问题,即用户从型号名称中删除空格,但源数据将其存储为单独的分词。
假设与验证
本文假设:
- 使用 SQL 示例创建的 RT 表完全按照所示方式创建
- 默认分词,除非示例明确更改了设置
- 型号名称中使用 ASCII 数字,因为
second_numeric和second_has_digit是围绕0-9构建的数字感知模式
本文中所有 SQL 示例和预期输出在发布前都已通过真实的 Manticore 23.0.0 实例验证,每个场景都使用从头开始创建的新表进行测试。
更广泛搜索问题
想象一个包含以下内容的目录:
xt 850 action cameraiphone 5se battery casecanon eos 80d bodythinkpad x1 carbon
现在想象用户搜索:
xt850iphone5seeos80dthinkpadx1
从用户的角度来看,这些显然应该匹配。但从引擎的角度来看,它们通常不会匹配,因为索引文本被分词为单独的术语。
搜索系统通常通过以下四种方式之一解决这种不匹配:
- 索引前缀或中缀
- 添加自定义规范化规则
- 将内容复制到备用规范化字段
- 索引相邻分词对,并可选地存储粘连变体
Manticore 的新 bigram 功能是一种结构化的方法,可以在不进行笨拙字段复制的情况下实现第四种选项。
基线:为什么 xt850 默认失败
这是最简单形式的问题:
DROP TABLE IF EXISTS bi_default_demo;
CREATE TABLE bi_default_demo(title text);
INSERT INTO bi_default_demo VALUES
(1,'xt 850 action camera');
SELECT id, title FROM bi_default_demo WHERE MATCH('xt850');
预期结果:
Empty set
为什么这会失败?
因为文档被索引为两个单独的分词,xt 和 850,而查询是一个单独的分词,xt850。
默认情况下,Manticore 不会假设:
xt850应该拆分为xt+850- 或
xt+850也应可搜索为xt850
因此,这并不是一个拼写容错问题或短语问题。这是一个分词不匹配问题:索引看到两个分词,而查询提供了一个。
这就是新 bigram 设置旨在解决的差距。它们让 Manticore 以可以匹配粘连查询的形式索引选定的相邻分词对。
为什么 bigrams 在这里有帮助
bigram_index
可以帮助
短语加速
和型号名称匹配,在本文中我们专注于 xt 850 vs xt850 的问题。
关键思想很简单:
- 检测看起来像型号名称的相邻分词对
- 同时以粘连形式存储这些对
- 让查询如
xt850、iphone5se或thinkpadx1匹配空格文本
这就是 bigram_delimiter 的作用所在。
关于 bigram_delimiter 的说明
bigram_index 决定哪些相邻对有资格。
bigram_delimiter 决定有资格的 bigrams 如何存储:
true:仅内部分隔的分词none:仅粘连分词,如galaxy24both:两种形式都保留
从查询的角度来看,实际差异最容易理解:
- 使用
true时,Manticore 保留用于短语优化的内部 bigram 形式,但不保留用户面向的粘连形式,因此像xt850这样的查询将无法匹配xt 850 - 使用
none时,Manticore 仅保留粘连形式,因此xt850可以匹配xt 850,但你完全依赖这些对的粘连表示 - 使用
both时,Manticore 保留内部 bigram 表示和粘连形式,因此xt850可以匹配xt 850而不会牺牲普通短语查询和混合工作负载的行为
对于此用例,both 通常是更安全的默认值,因为它直接解决了用户可见的问题,同时保持对普通短语查询和混合工作负载的行为更少令人意外。
模式 1:second_numeric
bigram_index = second_numeric
bigram_delimiter = both
此模式针对第二个分词纯粹是数字的型号名称。
这在产品目录中很常见:
xt 850galaxy 24playstation 5pixel 8
这个想法很简单:用户经常将这些搜索为粘连术语,如 xt850、galaxy24 或 playstation5,即使源文本中存储的是带空格的形式。
second_numeric 仅在第二个分词是纯 ASCII 数字时存储该对。
使用它时:
- 你有产品世代和编号型号
- 用户经常在搜索中删除空格
- 第二个分词通常是数字
示例
DROP TABLE IF EXISTS bi_second_numeric_demo;
CREATE TABLE bi_second_numeric_demo(title text)
bigram_index='second_numeric'
bigram_delimiter='both';
INSERT INTO bi_second_numeric_demo VALUES
(1,'xt 850 action camera'),
(2,'galaxy 24 ultra'),
(3,'playstation 5 slim'),
(4,'iphone 5se case'),
(5,'canon eos 80d body'),
(6,'thinkpad x1 carbon');
然后逐个测试查询:
SELECT id, title FROM bi_second_numeric_demo WHERE MATCH('xt850');
+------+----------------------+
| id | title |
+------+----------------------+
| 1 | xt 850 action camera |
+------+----------------------+
SELECT id, title FROM bi_second_numeric_demo WHERE MATCH('galaxy24');
+------+-----------------+
| id | title |
+------+-----------------+
| 2 | galaxy 24 ultra |
+------+-----------------+
SELECT id, title FROM bi_second_numeric_demo WHERE MATCH('playstation5');
+------+--------------------+
| id | title |
+------+--------------------+
| 3 | playstation 5 slim |
+------+--------------------+
SELECT id, title FROM bi_second_numeric_demo WHERE MATCH('iphone5se');
Empty set
SELECT id, title FROM bi_second_numeric_demo WHERE MATCH('eos80d');
Empty set
SELECT id, title FROM bi_second_numeric_demo WHERE MATCH('thinkpadx1');
Empty set
这个边界就是该模式的全部重点:
24和5符合条件5se、80d和x1不符合条件
模式 2:second_has_digit
bigram_index = second_has_digit
bigram_delimiter = both
此模式是 second_numeric 的更灵活的兄弟模式。
当第二个分词包含至少一个 ASCII 数字时,它会存储该对。这使其更适配实际产品目录,其中型号标识符通常是混合的字母数字字符串:
xt 850iphone 5seeos 80dthinkpad x1
使用它时:
- 您的型号名称混合了字母和数字
- 用户经常在搜索中删除空格
- 您希望实现目录友好的匹配,而无需为表中的每一对进行索引
示例
DROP TABLE IF EXISTS bi_second_has_digit_demo;
CREATE TABLE bi_second_has_digit_demo(title text)
bigram_index='second_has_digit'
bigram_delimiter='both';
INSERT INTO bi_second_has_digit_demo VALUES
(1,'xt 850 action camera'),
(2,'galaxy 24 ultra'),
(3,'playstation 5 slim'),
(4,'iphone 5se case'),
(5,'canon eos 80d body'),
(6,'thinkpad x1 carbon'),
(7,'kindle paperwhite signature');
然后逐个测试查询:
SELECT id, title FROM bi_second_has_digit_demo WHERE MATCH('xt850');
+------+----------------------+
| id | title |
+------+----------------------+
| 1 | xt 850 action camera |
+------+----------------------+
SELECT id, title FROM bi_second_has_digit_demo WHERE MATCH('galaxy24');
+------+-----------------+
| id | title |
+------+-----------------+
| 2 | galaxy 24 ultra |
+------+-----------------+
SELECT id, title FROM bi_second_has_digit_demo WHERE MATCH('iphone5se');
+------+---------------------+
| id | title |
+------+---------------------+
| 4 | iphone 5se case |
+------+---------------------+
SELECT id, title FROM bi_second_has_digit_demo WHERE MATCH('eos80d');
+------+---------------------+
| id | title |
+------+---------------------+
| 5 | canon eos 80d body |
+------+---------------------+
SELECT id, title FROM bi_second_has_digit_demo WHERE MATCH('thinkpadx1');
+------+---------------------+
| id | title |
+------+---------------------+
| 6 | thinkpad x1 carbon |
+------+---------------------+
SELECT id, title FROM bi_second_has_digit_demo WHERE MATCH('kindlesignature');
Empty set
这通常更适合混合型号标识符,因为实际目录数据经常包含类似 5se、80d 或 x1 的形式,而不仅仅是像 24 这样的干净数字后缀。
如何在两者之间选择
如果您的搜索问题具体是“如何让 xt850 找到 xt 850?”,实用规则是:
- 当第二个标记仅为数字时,使用
second_numeric - 当第二个标记可能是混合形式(如
5se、80d或x1)时,使用second_has_digit
有一个实用的注意事项:在简单情况下,这与其它常见的文本处理设置兼容。启用 morphology='stem_en' 并启用词形规则时,xt 850 仍能匹配 xt850。
但这并不意味着这些设置会为您重写拼接的查询。在测试中,iphones 5 匹配了 iphones5,但未匹配 iphone5,即使启用了词干提取或词形规则将 iphones 映射到 iphone。因此简短的结论是:基本的 xt 850 与 xt850 匹配仍与词形和词形规则兼容,但如果您依赖这些功能,请测试您关心的确切查询形式。
最终要点
xt850 问题实际上并不只是关于一个产品名称。它涉及用户输入型号名称的方式与搜索引擎分词方式之间的更广泛不匹配。
从版本 23.0.0 开始,Manticore 提供了一种内置方法来处理这种不匹配,即通过 bigram_delimiter 加上针对数字的 bigram_index 模式,这比复制字段或发明自定义预处理管道要干净得多。
如果您的主要问题是短语搜索性能而非粘连型号名称匹配,请参阅 如何通过 bigram_index 提高短语搜索速度 。
