APTX博客

  • ACGN
  • Coding
  • DevOps
  • Daily
  • Share
  • Bangumi
APTX Blog
A Moe Blog Set Up By ミズキ
  1. 首页
  2. Coding
  3. 正文

MongoDB中文全文检索方案

2021年4月25日 1823点热度 3人点赞 0条评论

前言

MySQL 从 5.7.6版本开始内置了ngram全文解析器,支持了中文、日文、韩文分词等东亚汉字文化圈的语言索引。但是MongoDB直到4.x的版本都不能在社区版为中文提供良好的全文检索支持。(据说商业版是已经支持了)

所以要想在MongoDB中使用中文全文检索的话,要不然就借助外部的检索工具,比如常见的ElasticSearch等,但是毕竟ElasticSearch是用Java写的,需要大量的资源。(我们都用MongoDB了,结果检索引擎比数据库都麻烦)这显然不是我们(这些没有对这个有非常大的需求的)想要的效果。

当然我们说虽然MySQL已经支持了,但肯定仍然撼动不了ElasticSearch等专门搞这个的的地位

事实上,MongoDB在2.x版本就已经支持了英文等部分拉丁文的全文检索。他们最大的特点是以空格分词。所以我们可以巧用这一特性去模拟一下。如何去做呢,那就是手动分词。

手动分词

我们选用nodejieba进行分词,nodejieba底层是用C++实现的,性能很好。当然还有一个用Rust语言实现的版本,速度比较快(但是在保存数据时可能会有问题,我猜可能是因为并发的问题)顺便一提nodejieba对香港繁体/台湾正体支持不好,可以选择使用OpenCC提前转换一下字典,或是边分词边转换。

值得一提的是nodejieba提供的API都是阻塞的同步API,但是nodejieba并不涉及很慢的IO操作,只是计算操作

1、安装nodejieba

yarn add nodejieba

2、学习分词,可以见到效果还是很好的。

console.log(nodejieba.cut('不起眼女主角培育法', true)) //[ '不起眼', '女主角', '培育法' ]

3、nodejieba也提供了提取关键词的API,事实上我在查询的时候我发现在保存数据时保存关键词比分词准确率更精准一点。见后文

console.log(nodejieba.extract('不起眼女主角培育法', 10))

得到的结果是

[
  { word: '培育法', weight: 13.2075304714 },
  { word: '女主角', weight: 9.74179456862 },
  { word: '不起眼', weight: 9.6811699468 }
]

Mongoose保存数据

由于我使用了TypeScript,所以我会配合Typegoose使用,而不是使用Mongoose默认的Schema

1、建立接口,在这里我为key_words字段建立了全文索引。

@modelOptions({options: {customName: 'test_collection'}})
@index(key_words: 'text'})
export class IBook2 {
    @prop({trim: true})
    name!: string;

    @prop({type: () => [String]})
    key_words!: string[];
}

2、分词

const Book2 = getModelForClass(IBook2);
const converterToZH = new OpenCC('tw2s.json');//这里使用了OpenCC进行正体到简体转换
export const createTextSegmentation = async (str: string) => {
    str = (await converterToZH.convertPromise(str)).toLowerCase();
    return nodejieba.extract(str, 10).map(v => v.word) || [str];
}

3、保存数据

const key_words = await createTextSegmentation('不起眼女主角培育法')
await Book2.create({
        name: '不起眼女主角培育法',
        key_words
});

查询数据

通过索引查询,所以还是比较省时间的。

const key_words = await createTextSegmentation('不起眼女主角培育法')
const result = await Book2.find(
        {
            $text: {
                $search: query
            }
        }, {
            score: {$meta: "textScore"}
        }
    ).sort({score: {$meta: "textScore"}});
console.log(result)

检索权重

...

 

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可
标签: Arch C++ OI RIP ST 模拟
最后更新:2021年4月25日

神楽坂 みずき

萌萌萌,好萌!

点赞
< 上一篇
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

神楽坂 みずき

萌萌萌,好萌!

搜索
最新 热点 随机
最新 热点 随机
站点域名变更通知 私たちの居る理由 《サクラノ詩》VI 章 直哉与蓝对话 从《AMRITA》到《HELLO WORLD》── 野﨑まど世界观下的个体与世界的真实感 几种云端 VSCode/类 VSCode 方案对比与部署 Summer Pockets REFLECTION BLUE 豪華限定版 早期予約色紙付き/通販・店舗対応版
关于斐讯N1刷机Linux(Armbian)及NAS两三事 C/C++字符串哈希(单哈希)Hash算法 模板 来自国外的优秀远控Darktrack Alien推荐 《Your Name》同人小说/相同时间线 我没有经验,还真是抱歉呢 #C/C++#二分图匹配匈牙利算法模板(邻接表/邻接矩阵)
标签聚合
C++ HTML 洛谷 ST 动漫 OI 日常 C/C++
分类
  • ACGN
  • Coding
  • Daily
  • DevOps
  • OI
  • Share

COPYRIGHT © 2017-2022 APTX博客. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang