1) 在window系统中,能够指定磁盘中的某一个位置来搜索你想要获得的东西。这个功能是windows比较经常使用的功能。java
2) 在eclipse中,帮助文档搜索:heltp 》help content,文件搜索ctrl+h,ctrl+shift+R.sql
其实eclipse的搜索功能就是用lucene写的数据库
3) 在百度和google 中,能够搜索互联网中的信息,有:网页、pdf、word音频、视频等内容。apache
4) Taobao搜索商品。windows
l 一般用于在大量数据出现的系统中,找出你想要的资料。常见的有缓存
l baidu贴吧框架
l 商品网站的搜索等eclipse
l 中关村在线 商品的名称、电脑硬件名称 (CPU)iphone
l 文件管理系统工具
l 对文件的搜索功能。Window的文件搜索
l 是针对 某个行业的搜索引擎
l 是搜索引擎的细分和延伸
l 是针对网页库中的专门信息的整合
l 其特色是专、深、精,并具备行业色彩
l 能够应用于购物搜索、房产搜索、人才搜索
l 从大量的信息中快速、准确地查找出要的信息
l 搜索的内容是文本信息(不是多媒体)
l 全文检索只是一个概念,而具体实现有不少框架,lucene是其中的一种,常见的还有solr,es等。其实solr和es底层也是lucene,只是作了一些封装。
lsql:好比我要查找某个商品,根据商品名,好比select * from product where doctname like %keywords%,这样查询的话对于数据量少是能够的,但是一旦你的数据量巨大几万几十万的时候,你的性能将会极大的减弱。
l lucene:在索引库里面会把全部的商品名根据分词器创建索引,就比如新华字典,索引对应document,好比输入衬衫,那么就会根据索引迅速的翻到衬衫对应的商品名,时间迅速,性能很好。
因为lucene的版本很是多,目前从apach官网上能下载到完整jar包的版本目前只有5.5.2和6.2.0,所以这里选择5.5.2版本,5.5.2版本所须要的jdk须要1.7。
http://apache.fayea.com/lucene/java/5.5.2/
一、 lucene-core-5.5.2.jar(核心包)
二、 lucene-analyzers-common-5.5.2.jar(分词器)
三、 lucene-backward-codecs-5.5.2.jar(兼容老版本)
四、 lucene-queryparser-5.5.2.jar(查询解析)
1. 建立IndexWriter对象
a) 须要指定索引库的位置,索引库的位置多是磁盘,也有多是内存。
b) 须要指定用什么分词器,由于建立索引的时候,会按照必定的切份内容的方式去建立索引,这样才能经过关键字查找到对应的内容。
2. 把JavaBean转化为Document
a) Javabean的每个字段就表明一个field,一个javabean就表明一个document。
3. 利用IndexWriter.addDocument方法增长索引
a) 说明:关于这个方法,实际上作了两件事情,先是建立好内容,再根据指定的分词器分词出关键字,建立索引目录。
4. 关闭IndexWriter
说明:使用完以后,要关闭掉资源,由于这里有io流资源相关的操做。另一个缘由关闭indexwriter,同时会提交操做,这样才能建立索引成功。
IndexWriter:是增、删、改索引过程的核心组件。这个类负责建立新索引或者打开已有索引,以及向索引中添加、删除或者更新被索引文档的信息。
IndexWriterConfig:获取indexwriter所须要的对象,能够理解为获取indexwriter的一个设置对象,能够设定使用什么分词建立索引,也能够设定建立索引的方式,是追加仍是覆盖。
Directory:在数据库中,数据库中的数据文件存储在磁盘上。索引库也是一样,索引库中的索引数据也在磁盘上存在,咱们用Directory这个类来描述。
Analyzer:指定录入的内容按照切分红若干个关键词放入到目录库中。
Field:存放一个键值对。这么理解:相似于数据库的一个字段。Filed的实现有不少种,如:StringField、TextField、IntField。Field包含了三个属性:类型、name、value。不一样的实现体现了不一样的类型,name、value表明的是一对键值对的名称和值。
Document:这么理解:相似于数据库的一条记录。Document的结构为:Document(List<Field>)。
Store:一个枚举类,两个值yes和no,yes表明内容存放在索引库中,no表明内容不存放在索引库中,这里要注意是不存放内容,可是是否会做为索引关键词是另外一回事。
注:关于上面状况下使用IntField,StringField,TextField的问题。
IntField:主要在保存相似数量,例如库存数量,须要常常用到范围查询的时候。使用这个字段保存的数据,没法经过正常的关键字查找到。
StringField:不须要分词,须要精确匹配的这段,如数据库的id,地理名等。
TextField:须要分词的字段
1. 建立IndexSearch
a) 须要拿到indexReader对象
2. 建立Query对象
3. 进行搜索
4. 根据获取到的TopDocs,得到总结果数和前N行目录ScoreDoc。
5. 根据目录ID列表获取到document。indexSearcher.doc(int)。
IndexSearch:是查索引过程的核心组件。
QueryParser 解析用户的查询字符串进行搜索,是一个解析用户输入的工具,能够经过扫描用户输入的字符串,生成Query对象。
Query:查询对象。封装要查询的相关信息。
TopDocs:索引库目录的一个引用。能够理解为搜索到的目录结果集的引用。主要包含了两个信息,总的记录数和目录结果集。
ScoreDoc:一条目录。包含了得分和索引下标。
说明:获取到的indexwriter必定要关闭,缘由和建立索引的缘由同样。
lucene的更新操做与数据库的更新操做是不同的。由于在更新的时候,有可能变换了关键字的位置,这样分词器对关键字还得从新查找,并且还得在目录和内容中替换,这样作的效率比较低,因此lucene的更新操做是删除和增长两步骤来完成的。
注:关于索引库优化。
旧版本:每执行一次就生成一个cfs文件。若是增长、删除反复操做不少次,就会形成文件大量增长,这样检索的速度也会降低,因此咱们有必要去优化索引结构。使文件的结构发生改变从而提升效率。
新版本当达到一个数量后会自动优化。
优化lucene能过forceMerge方法来将当小文件达到多少个时,就自动合并多个小文件为一个大文件,由于它的使用代价较高不意见使用此方法,默认状况下lucene会本身合并。
在内存中开辟一块空间,专门为索引库存放。这样有如下几个特征:
1) 由于索引库在内存中,因此访问速度更快。
2) 在程序退出时,索引库中的文件也相应的消失了。
3) 若是索引库比较大,必须得保证足够多的内存空间。
根据Directory不一样的子类获取到内存索引仍是文件索引库。建立索引的操做基本相似。
步骤:切分关键词
去除停用词
转为小写(搜索时不区分大小写,由于分词器会帮你转化)
如:I am a programmer,live in shenzhen,what about you?
分词后的结果为:
i
am
programmer
live
shenzhen
what
about
you
分词代码(无需研究没有什么意义,看分词后的结果就行了):
/** * 英文分词器 */ @Test public void testEnAnalyzer() throws Exception{ Analyzer analyzer = new StandardAnalyzer(); String text = "I am a programmer,live in shenzhen,what about you?"; this.testAnalyzer(text, analyzer); } /** * 中文分词器ik */ @Test public void testIKAnalyzer() throws Exception{ Analyzer analyzer = new IKAnalyzer(); // String text = "我是一名程序猿,居住在深圳,你呢?"; String text = "立创商城"; this.testAnalyzer(text, analyzer); } private void testAnalyzer(String text , Analyzer analyzer) throws Exception { TokenStream ts = null; try { ts = analyzer.tokenStream("myfield", new StringReader(text)); // 获取词元文本属性 CharTermAttribute term = ts.addAttribute(CharTermAttribute.class); // 重置TokenStream(重置StringReader) ts.reset(); // 迭代获取分词结果 while (ts.incrementToken()) { System.out.println( term.toString()); } // 关闭TokenStream(关闭StringReader) ts.end(); } catch (IOException e) { e.printStackTrace(); } finally { // 释放TokenStream的全部资源 if (ts != null) { try { ts.close(); } catch (IOException e) { e.printStackTrace(); } } } }
1) 经常使用的分词器有:IKAnalyzer、paoding、mmseg4j、imdict。 这里选用:IKAnalyzer
2) 如何自定义扩展词汇:将IKAnalyzer.cfg.xml拷贝到src下,而后新建一个本身的自定义词典,配置IKAnalyzer.cfg.xml便可。
源码分析入口:
初始化最主要的工做就是读入词典,并将这些词放入内存字典树
1.main2012.dic(关键词)2.quantifier.dic(量词)3.stopword.dic(停用词,可扩展)4.ext.dic(扩展词,可选)
注意:自定义的词汇文件要注意编码格式:UTF-8无BOM格式,不然分词会没有做用。
关于中文分词器,一定会有一个默认的词库文件。
IK Analyzer2012支持 细粒度切分 和 智能切分。
样例:
1)文本原文:
IKAnalyzer是一个开源的,基于java语言开发的轻量级的中文分词工具包。从2006年12月推出1.0版本开始,IKAnalyzer已经推出了3个大版本。
智能分词结果:
ikanalyzer | 是 | 一个 | 开源 | 的 | 基于 | java | 语言 | 开发 | 的 | 轻量级 | 的 | 中文 | 分词 | 工具包 | 从 | 2006年 | 12月 | 推出 | 1.0版 | 开始 | ikanalyzer | 已经 | 推 | 出了 | 3个 | 大 | 版本
最细粒度分词结果:
ikanalyzer | 是 | 一个 | 一 | 个 | 开源 | 的 | 基于 | java | 语言 | 开发 | 的 | 轻量级| 量级 | 的 | 中文 | 分词 | 工具包 | 工具 | 包 | 从 | 2006 | 年 | 12 | 月 | 推出 | 1.0 | 版 | 开始 | ikanalyzer | 已经 | 推出 | 出了 | 3 | 个 | 大 | 版本
Lucene的分页,总的来讲有两种形式。
原理:在lucene里面,每个索引内容都会对应一个不重复的docid,而这一点跟Oralce数据库的伪列rownum同样,偏偏正是因为这个docid的 存在,因此让lucene在海量数据检索时从而拥有更好的性能,咱们都知道Oracle数据库在分页时,使用的就是伪列进行分页,那么个人lucene也是同样,既然有一个docid的存在,那么就能够把数据所有拿到内存中,根据docid进行分页。
编码实现:
原理:先拿到上一页最后一个ScoreDoc,利用lucene提供的SearchAfter和获得的ScoreDoc查询当前页的索引结果。
编码实现:
两种方式的优缺点对比:
编号 |
方式 |
优势 |
缺点 |
1 |
在ScoresDocs里进行分页 |
无需再次查询索引,速度很快 |
在海量数据时,会内存溢出 |
2 |
利用SearchAfter,再次查询分页 |
适合大批量数据的分页 |
再次查询,速度相对慢一点,但能够利用缓存弥补 |
关键字查询,不分词。
Query query = new TermQuery(new Term("id", "1"));
查询全部。
Query query = new MatchAllDocsQuery();
通配符查询。?:匹配任意一个字符,*匹配多个任意字符
Query query = new WildcardQuery(new Term("name","i?"));
同个字段多个关键字组合查询,而且的关系。不分词,关键字区分大小写
Query query = new PhraseQuery("name", "iphone","6plus");
多个字段关键字组合查询
BooleanQuery.Builder booleanQuery = new BooleanQuery.Builder();
booleanQuery.add(new TermQuery(new Term("name", "iphone")), Occur.MUST);
booleanQuery.add(new TermQuery(new Term("description", "grey")), Occur.MUST);
Query query = booleanQuery.build();
范围查询,只针对IntField、FloatField这些数字类型的Field才能进行范围查询。
Query query = NumericRangeQuery.newIntRange("id", 1, 2, true, true);
说明:第四个参数和第五个参数,表明是否大于等于的意思,true即为包含。
观察源码,关于IndexSearcher.search有不少重载的方法,其中有方法能够传递Sort对象进去实现排序,以下图:
构造Sort字段实现排序,其中,这里要注意Lucene5.x的排序相比lucene4.x以前改动较大。
主要在排序字段须要在创建索引的时候单独指定,即不能根据索引的内容字段或者关键字字段去排序。以下图,若是某个字段须要支持排序,须要额外构建下面类型的Field字段,不然没法排序。
编码实现:
IK分词器:http://pan.baidu.com/s/1dFMcxnb
luke:http://pan.baidu.com/s/1dE0N2d7