Telegram 中文搜索方案探索
因为过年忘记带上电脑的电源适配器,好久没有更新博客了。生活总是稀疏平常,随着时间的推移,愈发觉得有些东西其实寥寥数语就可以讲完,无需长篇累牍地写上一篇长文。或许这是频道写多的弊端,就像让习惯了微博的人去写博客一样,内心必然是比较抵触的。但博客这种载体好就好在文字可以随着时间沉淀下来,记录自己思考和成长的过程,快餐式的频道内容无法与之相提并论。
本文写在为频道部署按关键词索引的机器人之后,顺带盘点一下 IT 社群和自留地为了让大家更为迅速地寻找自己想要的内容,做过了哪些努力。请注意,并没有一劳永逸解决全平台群组和频道中文搜素问题的方案。由于我个人对索引群友发言存在精神洁癖,因此这篇文章的受众是 TG 频道主。
Telegram 中文搜索现状
照例还是要啰嗦几句,讲讲我为什么要针对中文搜索下如此大的功夫。
Telegram 目前的搜索逻辑是根据「单词」来进行的,请注意这里的「单词」不一定是常见的单词,前后含有空格和标点符号则自成「单词」。譬如:Newlearner 如果写成“[空格] New lear ner [空格]”,那么在搜索中,你可以找到 New、lear、ner 这三个「单词」 。
这个搜索逻辑不可避免地带来一些问题,由于中文字与字之间是连贯没有空格的,如果你想要搜索某个历史关键词来找到之前的消息,可以说是很困难的。让我再次举例比较一下:
随着越来越多新朋友的加入,日聊天数量越来越多,有必要减少一些无关话题以保证群聊的高话题相关性。相关性不高的话题建议大家去对应群聊讨论
随着越来越多新朋友的加入,日聊天数量越来越多,有必要减少一些 无关 话题 以保证群聊的高 话题 相关性。相关性不高的 话题 建议大家去对应群聊讨论
可以看到第二段的“话题”一词前后都有空格,我如果想要搜索到这段话(群置顶),只需要搜“无关 话题”即可。而第一段话则搜索不出任何结果。九歌有一句鸽人鸽语叫做:“反正只要足够香,你的眼神就可以不要。”而我每次想要 forword,需要搜索“你的眼神就可以不要”才可以找到这句话。
那么中文搜索逻辑如此,含大量空格的英文搜素体验会好吗,或许如此。但 Telegram 的搜索始终做不到类似浏览器关键词那样的「拆词」,搜索“New”是找不到“Newlearner”的。和中文一样,很多小语种也被这套搜索的逻辑深深地困扰。
从 Telegram 搜索逻辑入手
所以 Telegram 中文搜索难用已成事实,我将从 Telegram 搜索逻辑入手,和大家分享一下我前期做过什么努力。
- 为频道消息打 Tag
- 频道群组聊天时,将关键词前后空格
- 含有英文的句子中,将英文前后空格
通过以上步骤,就将「我记得某消息有个关键词叫…」的问题转化为「某消息我当时打了什么 Tag、其中是否含有关键词(英文)」。
这里附上一张我们不对外公开的、主编内部材料:自留地 Tag 列表(不完整)
在实际操作的过程中,我们觉得自己需要这么一张 Tag 表,便于对消息进行一个大致的分类和便于搜索。但随着时间的推移,消息数量的累计,Tag 起到的只剩下一个分类的作用,且分类后消息数量依然庞大。不得不采用 Tag + 英文关键词这样的方式使这套机制正常运作。
因此弊端非常明显:
- Tag 太多让读者无法自动联想和对号入座,有时候频道主编也不能。而过于宽泛的 Tag 带来的依然是海量的信息量
- 空格是个好文明,但不是所有的群友和频道主都能在聊天和编辑频道内容中做到
基于此我们认为,脱离 Telegram 的搜索体系,采用全局爬虫才是这个问题的最优解,目的是实实在在地让大家通过「关键词」去探索频道内容或寻找之前消息。
手动整理的尝试
既然决定脱离 Telegram 这个搜索框架,我首先想到了自己的博客。博客是一个公开的内容展示平台,且可以配合浏览器进行无死角的关键词搜索。于是在去年12月份,我开始了艰难的手动频道内容整理,详见 Newlearnerの自留地导航页
经过两天的手动整理,我把具有实用性的技巧、文章、源码、软件工具等收录到这个导航页,形式是标题+链接。关注自留地的老读者都知道,我们之前每天推送信息的数量较多,其中夹杂着大量的时效性、羊毛新闻等。这个导航页主要目的有二:提供一个简单的分类、便于读者们搜索。
网站上线以来,阅读量近 5K。说实话并不算很多,我认为一方面不是每个读者都有搜索的需求,另一方面打开网页搜索体验确实没有 Telegram 内直接搜索来得直接。
基于 Web 的搜索引擎
在今年1月份,为了进一步优化大家的搜索体验,我和 sssoou.com 站长达成合作,将自留地展示于首页便于大家勾选并进行搜索。这种网页爬虫+搜索引擎的方案我比较喜欢,使用起来也确实很方便。
基于 Pyhton 的索引 Bot
上面的两套方案都跳出了 Telegram,转战浏览器,有些读者可能认为这样的体验不太好。因此近日我决心搭建一个关键词搜索 TG Bot,这样在兼顾体验的同时能够快速找出自己想要的消息。
方案选择
首先在 GitHub 上找到了几套方案:
- telegram-search:可按日期搜索的中文分词引擎机器人(针对频道)
- telegram-search-bot:Telegram 中文搜索复读机器人(针对群组)
- telegram-find-in-channel-bot:Telegram 中文搜索 Bot(针对频道)
由于无需细说的自留地和 IT 社群附属关系,我们打算为频道做一个关键词搜索机器人。相比第一个项目提供搜素结果展示/选择界面,第三个项目则直接将所有相关消息暴力 forword,因此体验很差。经过一番比较,我们决定使用 telegram-search 作为机器人搭建方案。
部署
部署过程中得到了开发者 EEYHN 的无私帮助,在这里先表示感谢。大致部署过程如下:
#申请机器人 && clone 到本地 git clone https://github.com/EYHN/telegram-search.git #安装依赖 pip install -r requirements.txt #修改 main.py && 创建 session 文件夹 mkdir session #生成数据库文件 python main.py #针对小内存机器,建立 Swap(1G),并 sysctl -w vm.max_map_count=262144 #修改 main.py 中 Docker 环境参数 ES_JAVA_OPTS=-Xms512m -Xmx512m #安装 docker 相关环境并运行 docker-compose up -d
运行之后机器人会实时抓取频道消息,并使用 elasticsearch 建立搜索引擎,整个项目对内存大小有一定的要求。如果你想要修改结果展示的字数,可以在 main.py 中找到相关代码,默认值为 15 个字符。
使用
机器人使用的是 Lucene 查询语法,可以精准到关键字词、日期。很多朋友直接输入关键词,对结果产生了很多疑问和不满,这里也来统一解答一下。先举个例子,例如我需要查询含有“动森”(动物森友会)的频道消息:
- 直接输入“动森”查询,会发现结果很多。这是由于未遵循查询语法,结果将含有“动”和“森”的所有消息全部列出。
- 当根据语法要求,输入“+动森”,会发现结果依然很多。这是因为词库并不认为「动森」是一个名词,而将含有“动”和“森”的所有消息全部列出。
- 因此正确的做法是,输入“+动 +森”,这表示搜索所有既含有“动”又含有“森”的消息。
总结与其他思路
照例来一张表格做一个横向对比:
基于 Telegram 框架 | 支持分类 | 按日期搜索 | 准确搜索关键词 | 备注 | |
---|---|---|---|---|---|
Telegram 自带搜索 | ✓ | ✗ | ✓ | ✗ | 对中文搜索不友好 |
Tag 与空格 | ✓ | ✗ | ✓ | ✗ | 操作难度大 |
自留地导航(博客) | ✗ | ✓ | ✗ | ✓ | 人力付出多 |
Web 搜索引擎 | ✗ | ✗ | ✗ | ✓ | 精确但需要浏览器和站主收录 |
Telegram 索引 Bot | ✓ | ✗ | ✓ | ✓ | 精确、基于 TG 但需要自学搜索语法和服务器开销 |
通过以上表格,相信大家对本文介绍的几种方案有了一个更直观的认知。在 Telegram 没有打算添加非英语语种的分词搜素措施前,我们应该不断寻找方法,改善群友和读者的搜索体验。最后附上我想到的其他思路:
- 对于个人:Windows 端支持导出频道全部内容,将其放置于浏览器,并加以搜索即可
- 对于群主/频道主:可以做一个关键词回复机器人,触发某关键词回复相关内容或者链接。但操作难度大、关键词并不明确且无法满足所有人的需求,只能做一些常用的,也称不上「搜索」或者「索引」
最后啰嗦一句,以上方案并不一定适合每位频道主,在信息累积到一定量之前简单的方法见效还是不错的。譬如我作为一个频道主,更新频率不高,每次更新完之后在 Notion 等处记录下 Tag、关键词和标题链接等重要信息,也可以做到自我索引。索引,既方便了自己,也方便了频道读者,因此非做不可。
希望以上内容为其他频道主提供一些有益的思路。更重要的是,让我们的读者了解到我们为了让大家有一个良好的搜索环境,做了哪些跨平台的方案。