亿级订单表 要对物流追踪号支持 LIKE %123% 这样的前后缀都模糊查询,现在的 MySQL 查一次要几分钟,必须上 ES 或者 ClickHouse 吗?另外归档数据也要查,有没有办法压缩存储数据

21 天前
 drymonfidelia
8386 次点击
所在节点    数据库
106 条回复
hedwi
20 天前
每家店应该只搜自己店的 这样加一个条件就从亿级别问题变成千万级别的问题了
drymonfidelia
20 天前
@hedwi 千万级没索引还是慢
Morriaty
20 天前
@Jinnrry 楼主提的需求应该是任意长度的匹配,如果用 n-gram 来配置,就要配置 min_gram:1, min_gram: N ,产生的索引量级就是 O(N**2 )。至于 pattern analyzer ,我没有看明白是怎么满足需求的
Morriaty
20 天前
打错:min_gram:1, max_gram: N
laminux29
20 天前
@sockpuppet9527

这玩意也是分词机制,你仔细看看你发的链接。分词与近似策略是无法精确处理这类需求的。所以我在开始就说了,这类需求,就没办法用索引。

业内目前应对这部分问题,第一是不处理。很多电商平台通过关键字搜索历史订单时,会发生这种情况,搜不出来;然后是通过剪枝需求去做的,比如银行只允许搜最近 3 个月的交易记录。
laminux29
20 天前
@iseki

分词与近似策略是无法精确处理这类需求的。所以我在开始就说了,这类需求,就没办法用索引。

recheck 只能解决假阳性,解决不了假阴性。

你说你们这边线上在用,没什么大问题,那是因为你们没发现问题,而且用户也没汇报。不仅如此,就连大电商平台,比如淘宝京东的历史订单号的搜索,因为他们采用分词搜索,所以他们也没办法实现这个需求。
Jinnrry
20 天前
@Morriaty #84 min_gram 设置成 1 ,max_gram 也设置成 1 就行了,他这个场景 max_gram 根本没意义。这样设置以后和我写的 pattern analyzer 分词结果是一样的。

比如“12345”这么一个订单号,分词结果为"1" "2" "3" "4" "5"

然后使用 match_phrase 查询 “123”或者“345”就都能查出来,match_phrase 是要求顺序和连续性的
iseki
20 天前
@laminux29 PG 的这个 trigram + GIN 很粗暴,不会有假阴性问题,缺点就是读放大有点大。
iseki
20 天前
这个东西的分词是 "12345" -> "123", "234", "345" 这种策略的,不会有你说的那种问题

@laminux29 存在类似风险时(比如输入长度小于 3 或者因为字符编码等问题没法搞),PG 会直接回退,放弃这个索引
iseki
20 天前
@laminux29
```
select show_trgm('12345');
show_trgm
---------------------------------
{" 1"," 12",123,234,345,"45 "}
(1 row)
```
Morriaty
20 天前
@Jinnrry 我还真没试过 NGram 和 match_phrase 的组合,直觉上会有很多误召回 badcase ,需要疯狂的调 `slop` 和 `minimum_should_match`🤣,把问题复杂化了,我还是倾向于,直接在需求设计上拒绝这种查询,改为全匹配或者前缀匹配
sockpuppet9527
20 天前
@laminux29 gin 是倒排索引,分词是另外的东西
lyxxxh2
20 天前
1. 匹配几亿太过了吧!
先固定在某个范围,不然用户 id 或者时间范围,降低模糊匹配的数量。

2. 如果真要匹配几亿:
建立一个 10 亿订单号的数组,作于自定义搜索索引,用程序语言来匹配 id,最后 whereIn 。
这应该是最快的方式。
dejavuwind
20 天前
@iseki #78 是我使用有什么问题么 结果验证就是会搜出来一堆错误结果的 recheck 需要主动配置?

难道这就是为什么一堆网站的所谓模糊搜索结果出来的内容根本匹配不上的原因?

dejavuwind
20 天前
@dejavuwind 不过效率倒还可以 但是这么用应该不算是合适方案
获取 5 条记录平均每条 250ms
获取 50 条平均每条大概 4-500ms
iseki
19 天前
@dejavuwind 你用的是相似度,我说的是 LIKE '%keyword%',咱俩说的不是一个东西啊
sampeng
19 天前
改 pg 是不可能的。业务在线上跑着呢。疯了,这个时候改存储方案。
才亿级数据而已。。es 有 es 的问题。。你还要考虑很多其他的事。

这个事就不是分词的事啊。。。我觉得是业务实现逻辑问题。如果只是物流号。自己给物流号自己建个 fst 结构索引就是了

我有几个方案:
1.sonic 。全 rust 开发,比 es 部署和维护都简单,也非常轻量,可以做一层全文搜索,但貌似无法做高可用? sonic 是有 fst 存储的。
2.既然是 mysql 。怎么没人提当年大名鼎鼎的 sphinx 呢? mysql 插件,代码是无缝集成。该写 sql 写 sql 。亿级,完全够用。
3.自己撸 fst 或者 lucene 。一起就 12 位的 fst 能有多大。每次新增的物流号时都刷新这个 fst 。从 fst 里面查然后提示给用户,用户选择要的那个。再去数据库拿原始数据。
sampeng
19 天前
我推测你们的功能其实是想输入一部分,然后快速提示这一部分所属的。
现成产品就是 sonic/es ,这两者都有提示词能力。都是基于 FST 等变种数据结构来做的。
自己撸一个也不是不可以,就是要考虑每一家的 fst 怎么存怎么取的问题。大致围绕这个逻辑来做。。。
dejavuwind
19 天前
@iseki #96 感谢回复。没用过这个 PG 的 pg_trgm ,被 #19 这个截图的语句给误导了,实际上使用 LIKE + pg_trgm 进行%xxx%的模糊查询才是正确的打开方式,而不是使用 similarity 进行查询
laminux29
19 天前
@sockpuppet9527

倒排索引不是用来解决楼主这个需求的。建议仔细看一下倒排索引的说明,然后找几个物流单号,用这种方法试试,你就明白了。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1086192

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX