介绍一款全文搜索引擎--lucene

作者:Qin Elaine
链接:https://zhuanlan.zhihu.com/p/21320272
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

今天我想给大家介绍的,是一款叫做lucene的开源搜索引擎。它是基于java环境下的,一款全文搜索引擎。如果你需要对非常多的文档进行搜索,可以考虑使用它。

lucene进行搜索
1. 通过对目标文档的处理,得到一个新的处理好的index。

这些index是长成这个样子的:在这里,lucene 所做的事情其实是把这些文档中的话先进行预处理。比如lucene会把"BitTiger" 转换成"bitgtiger" 也就是全部小写化。之后呢,lucene 会为你的文档建立一个matrix。这里我直接开始举例说明。
doc1 : "I love programming";
doc2: "programming is necessary skills and you should love it "


lucene 会建立如下的索引结构:



term docs location



I 1 1.0

love 1,2 1.2->2.47
programming 1,2 1.7->2.00
skills 2 2.26
and 2 ---
you 2 ---
it 2 ---
is 2 ---


term 代表出现在文档中的一个一个词语,docs代表的是这个文档的编号,lcoation代表的是词语出现在文档中的某个位置。在lucene当中,词语的位置是用一个linkedlist 串联起来的。

如果你要对一段文档进行索引,在API,你要做的事情很简单,我在这里直接贴代码
String path = "XXXXX"; ----------- 你文档的路径
final Path docDirs = Paths.get(Path);
// 你建立索引的路径
Directory dic_siwei = FSDirectory.open(Paths.get("你建立一个大索引的路径"));
Analyzer analyzer = new StandardAnalyzer(); ------ 构建分析器,它的作用是对文档语言进行处理
//配置索引writer和建立一个索引

IndexWriterConfig conf = new IndexWriterConfig(analyzer);
IndexWriter writer = new IndexWriter(dic_siwei,conf);
Document docs = new Document();
这里docDir是单独一个文件的路径,我省略了之前的一个方法,大家知道就行
InputStream stream = Files.newInputStream(docDir);
doc.add(new TextField("contents", new BufferedReader(newInputStreamReader(stream, StandardCharsets.UTF_8))));
writer.close();

这之后,你们就可以创建好一份索引。在这里你会问,如果我的添加了一个新的索引,那么我需不需要重新跑一次我的程序,去建立一个新的索引。在这里,lucene处理的很好。当你有新的文件需要进行处理,lucene提供了一个"updata" 接口可以将你的新内容加入到原来的索引文件中。

2.建立好索引之后如何进行搜索?
我觉得在这里,我想谈谈lucene的打分机制。比如我搜索“dota ti5”,我希望第一个搜索的结果文档叫做"dota2"而不是“英雄联盟(LOL)”.那么lucene是如何做的呢?
lucene 默认的搜索算法叫做TF/IDF 算法。

2.1(TF/IDF 算法)
TF-IDF算法全称为term frequency–inverse document frequency。TF就是term frequency的缩写,意为词频。IDF则是inverse document frequency的缩写,意为逆文档频率。
该算法在信息处理中通常用来抽取关键词。比如,对一个文章提取关键词作为搜索词,就可以采用TF-IDF算法。
要找出一篇文章中的关键词,通常的思路就是,就是找到出现次数最多的词。如果某个词很重要,它应该在这篇文章中多次出现。于是,我们进行"词频"(Term Frequency,缩写为TF)统计。
但是通常,一篇中文的文章中,都会有很多没有实际意义的词,比如“的”,“是”,“了”,这类词是最常用的词,称为停用词,称它们为停用词是因为在文本处理过程中如果遇到它们,则立即停止处理,将其扔掉。将这些词扔掉减少了索引量,增加了检索效率,并且通常都会提高检索的效果。停用词主要包括英文字符、数字、数学字符、标点符号及使用频率特高的单汉字等。
当过滤掉所有的停用词后,剩下的都是实际意义的词,但也不能简单的认为那个词出现的次数多就是关键词。比如在一篇如何组装电脑的文章中,出现“CPU”,“主板”等关键词和出现“说明书”的次数一样多,但很显然,CPU,主板等关键词,更能确定这个文章的特性。也就是说,“CPU”,“主板”等关键词比“说明书”这个关键词更重要,需要排在前面。所以我们就需要一个权重系数,用来调整各个关键词的重要性。如果一个词很少见,但是它在某个文章中反复出现多次,那么可以认为这个词反应了这个文章的特性,可以把它作为关键词。在信息检索中,这个权重非常重要,它决定了关键词的重要度,这个权重叫做"逆文档频率"(Inverse Document Frequency,缩写为IDF),它的大小与一个词的常见程度成反比。
在知道了词频和权重之后,两者相乘,就得到一个词的TF-IDF值,某个词对文章的重要性越高,它的TF-IDF值就越大。所以,排在最前面的几个词,就是这篇文章的关键词。
因此TF-IDF算法的主要工作就是计算出TF*IDF值最大的那几个词,作为文章的关键词。

可是,TF-IDF算法的优点是简单快速,结果比较符合实际情况。缺点是,单纯以"词频"衡量一个词的重要性,不够全面,有时重要的词可能出现次数并不多。而且,这种算法无法体现词的位置信息,出现位置靠前的词与出现位置靠后的词,都被视为重要性相同,这是不正确的。(一种解决方法是,对全文的第一段和每一段的第一句话,给予较大的权重。)
当通过TF-IDF算法找出文章的关键字后,可以运用到一些具体的场景。比如:根据关键字找出相似的文章。

2.2 代码怎么写?
//配置搜索器
IndexReader reade=DirectoryReader.open(FSDirectory.open(Paths.get(“你刚才建立索引的文件夹”)));
IndexSearcher searcher = new IndexSearcher(reader);

Analyzer analyzer = new StandardAnalyzer();
QueryParser parser = new QueryParser(field, analyzer);
Query query = parser.parse("你要搜索的内容");
// topDocs 就是就是你要得到的10个评分最高的文档
TopDocs results = searcher.search(query, 10);

2.3 其他算法扩展
如果你认为lucene本身的算法不够好,那么你可以考虑去实现其他的算法。比如BM25和BM25F算法。在lucene当中,如果你想更改原本的算法,那么你需要extends原来的Similarity类,然后将它配置到你的索引writer的配置中。如果你需要更好的索引。那么你可能需要为lucene重写很多代码,包括权重包(Weight),Query包(查询),Score包(打分)。

3.小小的展望
这是博主第一次写博客,真的第一次都献给了BitTiger啊有木有!博主表示如果文章写的不好,请见谅啊!

小组简介:亚特兰大地区小组Ranger,我们四个人都是CS相关专业的学生,三位GT一位Emory的。这里诚招一位兼职技术顾问,学生党经验不足啊!

作者:污妖王, 编辑:王思维,查看更多精彩博客文章bittiger.io/blog

更多内容,请访问:BitTiger.io, 扫描下面二维码,关注微信公众账号“论码农的自我修养”

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值