最先接触全文索引,还是在大学的时候,要给学校做一个搜索的项目,当初需求是能够提供类似百度的关键词搜索,但当时由于本身技术不行,虽然当时在网上找了一下资料,也看到了lucene,但当时学习的话,时间还是不够,而且有的难度,但当时已经知道可以用lucene来实现所需要的需求(当时项目中采用的方案是数据库多列合并like)。
后来就开始学习lucene,才知道什么是全文索引,由于lucene对因为索引搜索非常好,但对中文,则还需要安装相应的中文词库。再后来就接触到了solr,solr可以说是lucene的商业封装,可以绝大部分情况下,直接拿来用,操作非常简单,其实solr就是对lucene的封装,但建议还是先从lucene开始学起,lucene是一个底层。后来进入公司后,直接用的就是solr,当成一个独立的搜索服务。再后来由于公司的需要,就开始了解到了nutch,如果说solr是对lucene的一次封装,那么nutch就是再次对solr的再次封装,不仅仅提供搜索服务,而且还提供网络爬虫的功能。科技的发展真是越来越快,随着需求的不断升级,比如在nutch进行网络爬虫时,如果对全网进行爬虫,那么毫无疑问会产生大量的索引文件,已经不仅仅是几G了,而且这个时候索引,检索的速度也是非常慢的,这个时候便有了hadoop这个号称云应用的hadoop便诞生了。可以说hadoop是现代性发展的产物,也是未来的法阵趋势,它使多台计算机真正的高并发协作工作来完成一个任务成为可能。
下面就把我在学习lucene到solr以及nutch和hadoop以及工作的过程中所总结的资料分享一下,因为时间比较长了,留下的资料并不多,也不够全面。现在只是一个分享的过程而已。
lucene
创建索引
1 创建directory
目录分好几中,其中RAMDirectory创建在内存中,FSDirectory为基于文件的索引,自己会选择最好的文件索引。
2 创建IndexWriter
3 创建索引的“数据库“,每一行为一个document,含有好几个field列。
搜索
1 创建directory
2 创建indexreader
3 创建indexsearcher
4 创建搜索的Query对象
TermQuery 或者 QueryParse.parse(“”);
5根据searcher搜索并返回topdocs对象
6 根据topdocs创建sorcedoc对象
7 根据searcher和sorcedoc获取具体的Document对象
8 根据document对象获取需要的值
删除索引与恢复与合并
//参数是一个选项,可以是一个Query,也可以是一个term,term是一个精确查找的值
//此时删除的文档并不会被完全删除,而是存储在一个回收站中的,可以恢复
writer.deleteDocuments(new Term("id","1"));
writer.commit();
相反:
//恢复时,必须把IndexReader的只读(readOnly)设置为false
reader.undeleteAll();
或者
reader.deleteDocuments(new Term("id","1"));
强制删除:
writer.forceMergeDeletes();
//会将索引合并为2段,这两段中的被删除的数据会被清空
//特别注意:此处Lucene在3.5之后不建议使用,因为会消耗大量的开销,
//Lucene会根据情况自动处理的
writer.forceMerge(1);将多次索引合并一次索引
索引的更新
/*
* Lucene并没有提供更新,这里的更新操作其实是如下两个操作的合集
* 先删除之后再添加
*/
writer.updateDocument(new Term("id","1"), doc);
有reader.numDeletedDocs()多了一个,可以证明
加权
doc.setBoost(0.5f); 排序大小
存储与索引
Field.Store.YES或者NO(存储域选项)
设置为YES表示或把这个域中的内容完全存储到文件中,方便进行文本的还原
设置为NO表示把这个域的内容不存储到文件中,但是可以被索引,此时内容无法完全还原(doc.get)
Field.Index(索引选项)(分词和索引是不一样的,先分词再索引)
Index.ANALYZED:进行分词和索引,适用于标题、内容等
Index.NOT_ANALYZED:进行索引,但是不进行分词,如果身份证号,姓名,ID等,适用于精确搜索
Index.ANALYZED_NOT_NORMS:进行分词但是不存储norms信息,这个norms中包括了创建索引的时间和权值等信息
Index.NOT_ANALYZED_NOT_NORMS:即不进行分词也不存储norms信息
Index.NO:不进行索引
文件类型说明
.fnm 为存储域类型
.fdt .fdx为域的存储的值
.frq 为每个索引的次数,便于查询
.nrm 即norm,标分的信息
.prx 为偏移量
.tii .tis 为索引里的所有索引信息
.del 删除的文件都在这里面
注意:在默认(增量索引)索引时,每次都会添加新的索引,即在原来的基础上增加索引,即以0,1,2顺序递增,因此搜索时也会出现多个相同的值
l reader.numDocs() 有效的文档
l reader.maxDoc()=reader.numDocs()+reader.numDeletedDocs()
l sd.doc 文档的序号,整形
l sd.socre=doc.getboost+匹配度
l reader应该是单例模式,但当进行更改后应该重新初始化
reader = IndexReader.openIfChanged(reader);
l totalhit 总共命中
l searcher的分类
n 精确匹配查询 Query query = new TermQuery(new Term(field,name));
n 字符串范围的查询Query query = new TermRangeQuery(field,start,end,true, true);//是否包含最上面,最下面的
n 数字范围的查询 Query query = NumericRangeQuery.newIntRange(field,start, end,true,true);
n 前缀搜索 Query query = new PrefixQuery(new Term(field,value));
n 通配符搜索 Query query = new WildcardQuery(new Term(field,value));在传入的value中可以使用通配符:?和*,?表示匹配一个字符,*表示匹配任意多个字符
n 布尔搜索-多条件搜索
l BooleanQuery query = new BooleanQuery();
l /*
l * BooleanQuery可以连接多个子查询
l * Occur.MUST表示必须出现
l * Occur.SHOULD表示可以出现
l * Occur.MUSE_NOT表示不能出现
l */
l query.add(new TermQuery(new Term("name","zhangsan")), Occur.MUST_NOT);
l query.add(new TermQuery(new Term("content","game")),Occur.SHOULD);
n 短语查询
l PhraseQuery query = new PhraseQuery();
l //跳数,隔几个空格
l query.setSlop(3);
l // query.add(new Term("content","pingpeng"));
l //第一个Term
l query.add(new Term("content","i"));
l //产生距离之后的第二个Term
l query.add(new Term("content","football"));
n 模糊查询
l FuzzyQuery query = new FuzzyQuery(new Term("name","mase"),0.4f,0);
l System.out.println(query.getPrefixLength());//匹配前缀长度
l System.out.println(query.getMinSimilarity());//最小匹配长度
lucene-core-3.5.0.jar 是lucene的核心包,一般情况下只要有这个包就可以索引搜索了。
commons-io-2.1.jar 只是对文件进行操作的封装工具包。
lucene-memory-3.5.0.jar 是在lucene进行近实时搜索时用的缓存包。
lucene-highlighter-3.5.0.jar 是对lucene进行搜索后的结果进行关键字高亮的包。
mmseg4j-all-1.8.5-with-dic.jar 是中文插件包,可以让lucene支持中文分词,需要有词库(分词依赖)。
tika-app-1.0.jar 是对常用文件如excel,word,pdf 等的读取包。
这个还有一个比较重要的包lukeall-4.0.0-ALPHA.jar,这个包是个工具包,我们可以借助于这个包查看lucene的分词信息,见下图。