笨笨的思想片断

零碎片断,杂七杂八。
posts - 25, comments - 79, trackbacks - 0, articles - 0

中文全文检索的实现以及一些经验(Java)

Posted on 2007-07-30 17:55 笨笨 阅读(5373) 评论(10)  编辑  收藏 所属分类: Java

中文全文检索的实现以及一些经验(Java)


最近在项目中面临中文全文检索的需求,关键需求如下:

1 支持中文、英文字词的全文检索,待检索文本是古文言文。
2 全文检索表达式支持: AND,OR,NOT,NEAR,BEFORE 运算符,支持()。
3 速度要求:400M文本,要求在2-5秒内能够检索完毕。



尝试Lucene以及放弃原因:

在尝试Lucene和不同的中文Analyzer后,终告放弃。
原因如下:
由于待检索文本是古文,中文分词技术无法派上用场。在将分隔存储每个汉字后,发现从Lucene中检索到的文本远远少于关键字实际匹配的文本,这一问题对于较长的检索关键字尤其明显。
因为对于检索准确程度要求很高,故此放弃,但是Lucene出的这个问题的原因尚不清楚,希望能够有人提出解答。



自行实现中文全文检索原理以及方法:

1 构建过程,忽略标点符号,自行计算每个汉字在每个文本文件中的偏移量,并保存。
2 检索过程,定位每个汉字的偏移量,如果检索表达式中每个汉字的预期偏移量与实际偏移量吻合,则匹配成功。
3 采用 MappedByteBuffer 加快检索速度,采用二分查找加快偏移量匹配速度,3个左右的关键字复合检索能够在1秒内完成匹配(要求操作系统有足够大的缓存)。


目前实现的一些局限和优势:

0 中文检索速度足够,准确度比Lucene高(如果有高手能够解决这个问题,我会很高兴的废弃掉这些类的)
1 合适于中文,不适用英文文本
2 全文检索索引文件与原始文本文件的大小大约为2:3-3:4之间,300M大小,比Lucene大约多30M。
3 索引文件的构建时间长,400M大约需要3小时,同时由于如果任何文本文件更新,都需要重新构建索引文件,
因此不合适要经常变化的文本索引。




全文检索代码示例(TestFullTextQuery.java):
File storeDir = new File("C:\\temp\\fulltext\\index");
StoreSearcher searcher = new StoreSearcher(storeDir);
String str = "大?藏 & 阿难"; //同时出现 "大?藏" 和 "阿难", ?代表任意字符
searcher.queryBegin(str, true);
while(true){
    StoreSearcherResult ssr = searcher.getNextQueryResult();
    if ( ssr == null ){
        break;
    }
    System.out.println("ID "+ssr.docId+":"+ssr.matchedCount);
}
searcher.queryEnd();
searcher.close();

运行结果
ID T01n0001.TXT:320
ID T01n0002.TXT:3
ID T01n0004.TXT:2
ID T01n0005.TXT:202
ID T01n0006.TXT:131
....



附:全文检索表达式举例

关键字中间可以出现?,表明匹配任意字符。

运算符名称:运算符字符
AND:&
OR:,
BEFORE:*
NEAR:+
NOT:-

表达式举例:
(KEY1 <AND|OR|BEFORE|NEAR> KEY2) & (NOT KEY3)
KEY1 KEY2 (关键字之间无运算符假设为AND)



附:全文检索文件格式信息

DocInfoStore(文档信息)
--HEAD--
DocCount:Integer                    文档数目
--DOC HEAD(PER DOC)--
DocSeq:    Integer                        文档顺序号,内部使用
DocId:     Char[128]                    文档唯一ID,字符串格式
DocSepOfs: Integer                文档分隔符数组的Ofs
--DOC SEP OFS(PER DOC)--
DocOfs:    ArrayOfInteger        文档分隔数组


WordInfoStore(每个汉字信息)
--HEAD--
WordCount:Integer                    汉字数
--WORD IDX(Per Word)--
WordChar:Integer                    汉字的Unicode值
WordInfoOfs:Integer                汉字信息在文件中的偏移量
WordInfoSize:Integer            汉字信息大小
--WORD INFO(Per Word)--
DocCount:                                    汉字出现的文档数
DocSeq(Per Doc):                  每个文档的顺序号
WordInDocs:ArrayOfInteger 每个文档中出现的汉字的偏移数组,从小到大排列


源文件及CLASS下载地址:
http://www.blogjava.net/Files/zhugf000/foreader2_ftsearch.zip

Feedback

# re: 中文全文检索的实现以及一些经验(Java)  回复  更多评论   

2007-07-31 08:52 by BruceLuo
看一下。。。。。。

# re: 中文全文检索的实现以及一些经验(Java)  回复  更多评论   

2007-07-31 10:33 by princegsc
用正则表达式啊

# re: 中文全文检索的实现以及一些经验(Java)[未登录]  回复  更多评论   

2007-07-31 10:59 by 刘明
说起来,Lucene的性能似乎不行啊(我没测试过啊,只是网上资料说明)。似乎千万级别就比较慢了。前段日子用Lucene开发了个站内搜索(数据量大概在几百万吧),感觉无论是搜索(其实还好,在可接收范围内)和索引都有点慢。有没更好的实现啊?那些真正的能承受较大压力的搜索都是怎么开发的?谁知道?

# re: 中文全文检索的实现以及一些经验(Java)  回复  更多评论   

2007-07-31 14:59 by BruceLuo
都是的分布式的,索引和爬取基本上都是用的C++,WEB层用的是PHP,这是完美的结合!

# re: 中文全文检索的实现以及一些经验(Java)  回复  更多评论   

2007-07-31 17:08 by sitinspring
这个有技术含量.

# re: 中文全文检索的实现以及一些经验(Java)[未登录]  回复  更多评论   

2007-08-01 14:12 by 刘明
笨笨啊,我有点迷茫。能给解答一下吗?

公司的站内搜索OK了,但领导让我继续研究研究搜索,但我不知道该继续去研究什么好了。
中文分词?目前使用的模块(JE)还可以,如果自己研发需要不少时间,还有词库问题。
爬虫?我们是站内搜索,虽然头说站外也是个方向,但很不明确,我对没有明确需求的东西实在不感兴趣。
分布式?目前的量还没必要(几百万),差的很远的,而且如果一直站内搜索的话也很难用上。
缓冲?这个很有用,但目前实在没有太好的想法。

目前站内搜索的状况就是正常运行,没什么错误,也不知道该改些什么。很迷茫。(还有个项目相反,能正常运行,但我还有很多想法,但领导说我在那个项目浪费太多时间了,不许我再做了,能运行就行。-_-!)

最近很怪,我对搜索的研究很迷茫,对用户的需求倒是很感兴趣。我一直在思考自己的东西最终能给用户带来什么,如何让用户更加方便的使用。

嗯。。。就是很迷茫,有啥好的建议吗?

# re: 中文全文检索的实现以及一些经验(Java)  回复  更多评论   

2007-08-02 14:04 by active1001
用lucene检索的时候,结果少的原因,应该是,你查询的时候用的分词器不对。
在查询之前先把每个字直接加一个空格。例如:“中文检索”-》“中 文 检 索”。

# re: 中文全文检索的实现以及一些经验(Java)  回复  更多评论   

2008-06-18 15:40 by litao
很好的东西啊 呵呵 可惜缺少些jar

能不能送我啊 litao1258@126.com

多谢

# re: 中文全文检索的实现以及一些经验(Java)  回复  更多评论   

2008-07-01 15:12 by litao
东西已经收到,不胜感激!

# re: 中文全文检索的实现以及一些经验(Java)  回复  更多评论   

2008-08-11 11:46 by 小雨转晴
你好,笨笨,我刚刚研究lucene,现在面临的问题也是中文的全文检索,
我的问题正好和你相反,我返回的数据太多了。
比如搜索的keyword是[高考]会被拆分为[高][考]两个字进行检索。
这样的话检索大量数据的时候就会很慢,而且我做了关键字的高亮显示
这样一来,比如标题为【2008年北京考区高考状元】那么被高亮后为
2008年北京[考]区[高][考]状元,这样看起来很不好,怎么样可以按着【词】来
建立索引呢,然后按着【词】进行检索并高亮,头疼的问题,可以和您讨论一下嘛?
其他的朋友也欢迎讨论。希望您能联系我一下,QQ396615834 MSN wind_1121@hotmail.com 十分感谢。

只有注册用户登录后才能发表评论。


网站导航: