什么算法(思路) 能 快速的查找(搜索、索引) 包含 关键词的文档?
比如 有一个 对象 有 id,name 字段,然后 有一个 关键词 字段 words
比如 就叫 疾病
{ id : 1, name : "脑梗死", words : ["脑动脉供血不足","头晕","脑供血不足","头痛","咳嗽"] ..... } { id : 2, name : "高血压", words : ["偶感头晕","头晕","反复头晕","乏力","发作性头晕","头痛"] ..... } ....
要查询的词语为:
头晕;头痛;咳嗽
现在想 查询 的是: 完全包含 这组词语,但 不需要完全匹配, 顺序 也不需要 相同。
通常 数据库的模糊查询,或者 支持 数组查询 的数据库 查询 就行了.
可是 如果 需要 查询的 词组 有 很多,比如 1000万个,那从 数据库查询 效率就太低了。
假设 被查询的 疾病 不是特别多,可以 加载到内存,那应该 怎么高效的查询呢?
比如 我自己想 :
可以把 所有疾病 的关键词 拆分开 放入 键值对的形式 放入到 Map中:key 是 关键词,value 是 该疾病(一个疾病 会有多个key,一个 key 也 会对应 多个 疾病),
这样 需要 查询词组的时候 直接 用 该词组的的 每个 词语,从map中 按照 key 查询 ,java里 能直接 map.get(key),拿到包含其中一个词语的文章,这样就能过滤掉 很多。。。。。
然后呢。。。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(26)
试试 Solr
。。。谢谢
...以后会学习的..谢谢
另外还可以试试SQLite,这个文件型数据库也是支持全文检索的,读速度应该是非常非常快的,管理工具可以用SQLiteStudio2和3,可以考虑把文件放到内存/dev/shm/app/data.db3提供查询服务,速度快得肯定飞起!
补充说明一下,因为你的用户输入,以及words字段的内容,分词都是手工确定的,所以并不需要分词功能,而且因为手工分词,全文检索的准确度也会更高.FullText索引查询速度也远比LIKE模糊搜索快.
用神经网络 关键词提取 然后使用皮尔逊系数去处理 使用全文检索 把这几个维度合并到一块 排序
谢谢,在程序实现不了的情况下 会考虑你说的数据库的方式的。
嗯。。。 上面我的回复。。。
引用来自“CoCo丶Hu”的评论
倒排索引
据说MySQL的FIND_IN_SET(str,strlist)性能比LIKE模糊查询好点,可以试试:
SELECT * FROM `sickness`
WHERE FIND_IN_SET('头晕', `words`)
OR FIND_IN_SET('头痛', `words`)
OR FIND_IN_SET('咳嗽', `words`);
其中words字段中内容以逗号隔开:
脑动脉供血不足,头晕,脑供血不足,头痛,咳嗽
不过还是推荐用MySQL-5.6.4后InnoDB的FULLTEXT全文索引,这个是支持中文的.
my.cnf的[mysqld]的innodb_ft_min_token_size默认是3,因为你这里最小单词长度是两个字,所以应该设为2或者1.
[mysqld]
innodb_ft_min_token_size=2
CREATE TABLE `sickness` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(200) NOT NULL DEFAULT '',
`words` text,
PRIMARY KEY (`id`),
FULLTEXT (`words`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
INSERT INTO `sickness`(`name`, `words`)
VALUES ('脑梗死', '脑动脉供血不足 头晕 脑供血不足 头痛 咳嗽');
INSERT INTO `sickness`(`name`, `words`)
VALUES ('高血压', '偶感头晕 头晕 反复头晕 乏力 发作性头晕 头痛');
SELECT * FROM sickness WHERE MATCH(`words`) AGAINST('头晕 头痛 咳嗽');

回复
...
回复
不是,我意思是 我回复的 使用倒排索引 查询一次 得到 一批结果以后呢?如果不想对初步查询出来的的结果一条条的比对的话,有什么好办法吗?
回复
因为 我想的倒排索引的 形式 是: { A1:文档A ; A2:文档A ; A1:文档B ; } 如果 每个词语都是单个的词语的话,那么 不能直接把结果 查出来的 ,得进一步处理,对吧?
回复
{ A1:文档A ; A2:文档A ; A1:文档B ; } 变成{ A1:[文档A,文档B] ; A2:[文档A] ; }生成Map<Key,List>的形式
倒排索引
这不就是找3个(A,B,C)3个文档中的共同文档么?
引用来自“Altman”的评论
对
words分词做反向索引,然后对输入词做分词,然后去查词的文档序号,如果需要模糊查询需要做词/词意的相似性分析,然后慢慢就做成搜索引擎了
嗯。。。我更希望用程序的方式 实现。。不过 不行 的话 也考虑用这种方式吧。
mysql 是支持全文搜索的,不过对中文的支持不行
IK切词后,转拼音,然后把拼音存数据库,使用全文搜索就可以了
字段用fulltext,表需要用MyISAM
还有此方案实现容易,但是几乎没有可以优化和提升的余地
ORACLE好像也有类似的全文检索
没想到这个需求 最后 是搜索引擎的方向。。。
对
words分词做反向索引,然后对输入词做分词,然后去查词的文档序号,如果需要模糊查询需要做词/词意的相似性分析,然后慢慢就做成搜索引擎了
这就算搜索引擎了?。。。需求确实 有些像。。
搜索引擎是个大坑,慢慢填
其实我想问的 就是 “头痛”和“咳嗽” 当各自 查询到结果以后怎么办。。。也就是 你说的并集,那也就是说 最后 用 id 去重即可了。。谢谢。。
。。。不是去重,是取交集。。。谢谢了,也谢谢其他各位的热心帮忙。。
文档A 这个地方 不是真的放整个文档,只是一个标志,代表文档A,接着你就继续计算就是的啊。有2个文档A:["头晕","头痛"] B:["头痛","咳嗽"],A,B 肯定要持久化的,这是相对于DB而言就是A: id=10001,content=["头晕","头痛"] B:id=10002,content=["头痛","咳嗽"],而你的倒排索引就是:{"头晕":[10001,],"头痛":[10001,10002],"咳嗽":[10002]}。当你要取"头痛","咳嗽"时候,先获取:"头痛":[10001,10002]->T1,然后"咳嗽":[10002]->T2。然后计算并集就可以了啊。这样应该是够了的。如果觉得大数据计算很麻烦,参考BitMap的用法。原来的结构变成Map<Key,BitMap>这样的