Lucene 代码详解
来源:互联网 发布:跳蚤街二手市场软件 编辑:程序博客网 时间:2024/05/22 04:22
1.配置开发环境
(1) Lucene下载
Lucene是开发全文检索功能的工具包,从官方网站下载Lucene4.10.3,并解压。
官方网站:http://lucene.apache.org/
版本:lucene4.10.3
Jdk要求:1.7以上
IDE:Eclipse
(2) 使用的jar包
Lucene包:
lucene-core-4.10.3.jar
lucene-analyzers-common-4.10.3.jar
lucene-queryparser-4.10.3.jar
其它:
commons-io-2.4.jar
junit-4.9.jar
2.功能一:创建索引库
使用indexwriter对象创建索引
(1) 实现步骤
第一步:创建一个java工程,并导入jar包。
第二步:创建一个indexwriter对象。
① 指定索引库的存放位置Directory对象
② 指定一个分析器,对文档内容进行分析。
第三步:创建document对象。
第四步:创建field对象,将field添加到document对象中。
第五步:使用indexwriter对象将document对象写入索引库,此过程进行索引创建。并将索引和document对象写入索引库。
第六步:关闭IndexWriter对象。
(2) Field域的属性
是否分析:是否对域的内容进行分词处理。前提是我们要对域的内容进行查询。
是否索引:将Field分析后的词或整个Field值进行索引,只有索引方可搜索到。
比如:商品名称、商品简介分析后进行索引,订单号、身份证号不用分析但也要索引,这些将来都要作为查询条件。
是否存储:将Field值存储在文档中,存储在文档中的Field才可以从Document中获取
比如:商品名称、订单号,凡是将来要从Document中获取的Field都要存储。
是否存储的标准:是否要将内容展示给用户
(3) 代码实现
//创建索引 @Test public void createIndex() throws Exception { //指定索引库存放的路径 //D:\temp\0108\index Directory directory = FSDirectory.open(new File("D:\\temp\\0108\\index")); //索引库还可以存放到内存中 //Directory directory = new RAMDirectory(); //创建一个标准分析器 Analyzer analyzer = new StandardAnalyzer(); //创建indexwriterCofig对象 //第一个参数: Lucene的版本信息,可以选择对应的lucene版本也可以使用LATEST //第二根参数:分析器对象 IndexWriterConfig config = new IndexWriterConfig(Version.LATEST, analyzer); //创建indexwriter对象 IndexWriter indexWriter = new IndexWriter(directory, config); //原始文档的路径D:\传智播客\01.课程\04.lucene\01.参考资料\searchsource File dir = new File("D:\\传智播客\\01.课程\\04.lucene\\01.参考资料\\searchsource"); for (File f : dir.listFiles()) { //文件名 String fileName = f.getName(); //文件内容 String fileContent = FileUtils.readFileToString(f); //文件路径 String filePath = f.getPath(); //文件的大小 long fileSize = FileUtils.sizeOf(f); //创建文件名域 //第一个参数:域的名称 //第二个参数:域的内容 //第三个参数:是否存储 Field fileNameField = new TextField("filename", fileName, Store.YES); //文件内容域 Field fileContentField = new TextField("content", fileContent, Store.YES); //文件路径域(不分析、不索引、只存储) Field filePathField = new StoredField("path", filePath); //文件大小域 Field fileSizeField = new LongField("size", fileSize, Store.YES); //创建document对象 Document document = new Document(); document.add(fileNameField); document.add(fileContentField); document.add(filePathField); document.add(fileSizeField); //创建索引,并写入索引库 indexWriter.addDocument(document); } //关闭indexwriter indexWriter.close(); }
(4) 使用Luke工具查看索引文件
3.功能二:查询索引
(1) 实现步骤
第一步:创建一个Directory对象,也就是索引库存放的位置。
第二步:创建一个indexReader对象,需要指定Directory对象。
第三步:创建一个indexsearcher对象,需要指定IndexReader对象
第四步:创建一个TermQuery对象,指定查询的域和查询的关键词。
第五步:执行查询。
第六步:返回查询结果。遍历查询结果并输出。
第七步:关闭IndexReader对象
(2) IndexSearcher搜索方法
(3) 代码实现
//查询索引库 @Test public void searchIndex() throws Exception { //指定索引库存放的路径 //D:\temp\0108\index Directory directory = FSDirectory.open(new File("D:\\temp\\0108\\index")); //创建indexReader对象 IndexReader indexReader = DirectoryReader.open(directory); //创建indexsearcher对象 IndexSearcher indexSearcher = new IndexSearcher(indexReader); //创建查询 Query query = new TermQuery(new Term("filename", "apache")); //执行查询 //第一个参数是查询对象,第二个参数是查询结果返回的最大值 TopDocs topDocs = indexSearcher.search(query, 10); //查询结果的总条数 System.out.println("查询结果的总条数:"+ topDocs.totalHits); //遍历查询结果 //topDocs.scoreDocs存储了document对象的id for (ScoreDoc scoreDoc : topDocs.scoreDocs) { //scoreDoc.doc属性就是document对象的id //根据document的id找到document对象 Document document = indexSearcher.doc(scoreDoc.doc); System.out.println(document.get("filename")); //System.out.println(document.get("content")); System.out.println(document.get("path")); System.out.println(document.get("size")); } //关闭indexreader对象 indexReader.close(); }
4.功能三:支持中文分词
(1) 分析器(Analyzer)的执行过程
如下图是语汇单元的生成过程:
要看分析器的分析效果,只需要看Tokenstream中的内容就可以了。每个分析器都有一个方法tokenStream,返回一个tokenStream对象。 从一个Reader字符流开始,创建一个基于Reader的Tokenizer分词器,经过三个TokenFilter生成语汇单元Tokens。
(2) 分析器的分词效果
//查看标准分析器的分词效果 public void testTokenStream() throws Exception { //创建一个标准分析器对象 Analyzer analyzer = new StandardAnalyzer(); //获得tokenStream对象 //第一个参数:域名,可以随便给一个 //第二个参数:要分析的文本内容 TokenStream tokenStream = analyzer.tokenStream("test", "The Spring Framework provides a comprehensive programming and configuration model."); //添加一个引用,可以获得每个关键词 CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class); //添加一个偏移量的引用,记录了关键词的开始位置以及结束位置 OffsetAttribute offsetAttribute = tokenStream.addAttribute(OffsetAttribute.class); //将指针调整到列表的头部 tokenStream.reset(); //遍历关键词列表,通过incrementToken方法判断列表是否结束 while(tokenStream.incrementToken()) { //关键词的起始位置 System.out.println("start->" + offsetAttribute.startOffset()); //取关键词 System.out.println(charTermAttribute); //结束位置 System.out.println("end->" + offsetAttribute.endOffset()); } tokenStream.close(); }
(3) 中文分析器
① Lucene 自带中文分词器
【1】StandardAnalyzer:
单字分词:就是按照中文一个字一个字地进行分词。如:“我爱中国”,
效果:“我”、“爱”、“中”、“国”。
【2】CJKAnalyzer
二分法分词:按两个字进行切分。如:“我是中国人”,效果:“我是”、“是中”、“中国”“国人”。
上边两个分词器无法满足需求。
【3】SmartChineseAnalyzer
对中文支持较好,但扩展性差,扩展词库,禁用词库和同义词库等不好处理。
② 第三方中文分析器
【1】paoding: 庖丁解牛最新版在?https://code.google.com/p/paoding/?中最多支持Lucene 3.0,且最新提交的代码在 2008-06-03,在svn中最新也是2010年提交,已经过时,不予考虑。
【2】mmseg4j:最新版已从?https://code.google.com/p/mmseg4j/?移至?https://github.com/chenlb/mmseg4j-solr,支持Lucene 4.10,且在github中最新提交代码是2014年6月,从09年~14年一共有:18个版本,也就是一年几乎有3个大小版本,有较大的活跃度,用了mmseg算法。
【3】IK-analyzer: 最新版在https://code.google.com/p/ik-analyzer/上,支持Lucene 4.10从2006年12月推出1.0版开始, IKAnalyzer已经推出了4个大版本。最初,它是以开源项目Luence为应用主体的,结合词典分词和文法分析算法的中文分词组件。从3.0版本开 始,IK发展为面向Java的公用分词组件,独立于Lucene项目,同时提供了对Lucene的默认优化实现。在2012版本中,IK实现了简单的分词 歧义排除算法,标志着IK分词器从单纯的词典分词向模拟语义分词衍化。 但是也就是2012年12月后没有在更新,基本无敌了,市场老大。
【4】ansj_seg:最新版本在?https://github.com/NLPchina/ansj_seg?tags仅有1.1版本,从2012年到2014年更新了大小6次,但是作者本人在2014年10月10日说明:“可能我以后没有精力来维护ansj_seg了”,现在由”nlp_china”管理。2014年11月有更新。并未说明是否支持Lucene,是一个由CRF(条件随机场)算法所做的分词算法。
【5】imdict-chinese-analyzer:最新版在?https://code.google.com/p/imdict-chinese-analyzer/?, 最新更新也在2009年5月,下载源码,不支持Lucene 4.10 。是利用HMM(隐马尔科夫链)算法。
【6】Jcseg:最新版本在git.oschina.net/lionsoul/jcseg,支持Lucene 4.10,作者有较高的活跃度。利用mmseg算法。
(4) IKAnalyzer的使用
第一步:把jar包添加到工程中
第二步:把配置文件和扩展词典和停用词词典添加到classpath下
注意:mydict.dic和ext_stopword.dic文件的格式为UTF-8,注意是无BOM的UTF-8编码。
使用EditPlus.exe保存为无BOM?的UTF-8编码格式,如下图:
5.功能四:索引库的维护
(1) 索引库的添加
① 步骤
向索引库中添加document对象。
第一步:先创建一个indexwriter对象
第二步:创建一个document对象
第三步:把document对象写入索引库
第四步:关闭indexwriter。
② 代码实现
//添加索引 @Test public void addDocument() throws Exception { //索引库存放路径 Directory directory = FSDirectory.open(new File("D:\\temp\\0108\\index")); IndexWriterConfig config = new IndexWriterConfig(Version.LATEST, new IKAnalyzer()); //创建一个indexwriter对象 IndexWriter indexWriter = new IndexWriter(directory, config); //创建一个Document对象 Document document = new Document(); //向document对象中添加域。 //不同的document可以有不同的域,同一个document可以有相同的域。 document.add(new TextField("filename", "新添加的文档", Store.YES)); document.add(new TextField("content", "新添加的文档的内容", Store.NO)); document.add(new TextField("content", "新添加的文档的内容第二个content", Store.YES)); document.add(new TextField("content1", "新添加的文档的内容要能看到", Store.YES)); //添加文档到索引库 indexWriter.addDocument(document); //关闭indexwriter indexWriter.close(); }
(2) 索引库删除
① 删除全部
//删除全部索引 @Test public void deleteAllIndex() throws Exception { IndexWriter indexWriter = getIndexWriter(); //删除全部索引 indexWriter.deleteAll(); //关闭indexwriter indexWriter.close(); }//说明:将索引目录的索引信息全部删除,直接彻底删除,无法恢复,此方法谨慎使用!
② 指定查询条件删除
//根据查询条件删除索引 @Test public void deleteIndexByQuery() throws Exception { IndexWriter indexWriter = getIndexWriter(); //创建一个查询条件 Query query = new TermQuery(new Term("filename", "apache")); //根据查询条件删除 indexWriter.deleteDocuments(query); //关闭indexwriter indexWriter.close(); }
(3) 索引库的修改
原理就是先删除后添加。
//修改索引库 @Test public void updateIndex() throws Exception { IndexWriter indexWriter = getIndexWriter(); //创建一个Document对象 Document document = new Document(); //向document对象中添加域。 //不同的document可以有不同的域,同一个document可以有相同的域。 document.add(new TextField("filename", "要更新的文档", Store.YES)); document.add(new TextField("content", "2013年11月18日 - Lucene 简介 Lucene 是一个基于 Java 的全文信息检索工具包,它不是一个完整的搜索应用程序,而是为你的应用程序提供索引和搜索功能。", Store.YES)); indexWriter.updateDocument(new Term("content", "java"), document); //关闭indexWriter indexWriter.close(); }
6.Lucene索引库查询
对要搜索的信息创建Query查询对象,Lucene会根据Query查询对象生成最终的查询语法,类似关系数据库Sql语法一样Lucene也有自己的查询语法,比如:“name:lucene”表示查询Field的name为“lucene”的文档信息。
可通过两种方法创建查询对象:
(1) 使用Lucene提供Query子类
Query是一个抽象类,lucene提供了很多查询对象,比如TermQuery项精确查询,NumericRangeQuery数字范围查询等。
如下代码:
Query query = new TermQuery(new Term("name", "lucene"));
(2) 使用QueryParse解析查询表达式
QueryParse会将用户输入的查询表达式解析成Query对象实例。
如下代码:
QueryParser queryParser = new QueryParser("name", new IKAnalyzer());
Query query = queryParser.parse("name:lucene");
(1) 使用query的子类查询
① MatchAllDocsQuery
使用MatchAllDocsQuery查询索引目录中的所有文档
@Test public void testMatchAllDocsQuery() throws Exception { IndexSearcher indexSearcher = getIndexSearcher(); //创建查询条件 Query query = new MatchAllDocsQuery(); //执行查询 printResult(query, indexSearcher); }
② TermQuery
TermQuery,通过项查询,TermQuery不使用分析器所以建议匹配不分词的Field域查询,比如订单号、分类ID号等。
指定要查询的域和要查询的关键词。//使用Termquery查询 @Test public void testTermQuery() throws Exception { IndexSearcher indexSearcher = getIndexSearcher(); //创建查询对象 Query query = new TermQuery(new Term("content", "lucene")); //执行查询 TopDocs topDocs = indexSearcher.search(query, 10); //共查询到的document个数 System.out.println("查询结果总数量:" + topDocs.totalHits); //遍历查询结果 for (ScoreDoc scoreDoc : topDocs.scoreDocs) { Document document = indexSearcher.doc(scoreDoc.doc); System.out.println(document.get("filename")); //System.out.println(document.get("content")); System.out.println(document.get("path")); System.out.println(document.get("size")); } //关闭indexreader indexSearcher.getIndexReader().close(); }
③ NumericRangeQuery
可以根据数值范围查询。
//数值范围查询 @Test public void testNumericRangeQuery() throws Exception { IndexSearcher indexSearcher = getIndexSearcher(); //创建查询 //参数: //1.域名 //2.最小值 //3.最大值 //4.是否包含最小值 //5.是否包含最大值 Query query = NumericRangeQuery.newLongRange("size", 1l, 1000l, true, true); //执行查询 printResult(query, indexSearcher); }
④ BooleanQuery
可以组合查询条件。
说明:Occur.MUST:必须满足此条件,相当于and//组合条件查询 @Test public void testBooleanQuery() throws Exception { IndexSearcher indexSearcher = getIndexSearcher(); //创建一个布尔查询对象 BooleanQuery query = new BooleanQuery(); //创建第一个查询条件 Query query1 = new TermQuery(new Term("filename", "apache")); Query query2 = new TermQuery(new Term("content", "apache")); //组合查询条件 query.add(query1, Occur.MUST); query.add(query2, Occur.MUST); //执行查询 printResult(query, indexSearcher); }
Occur.SHOULD:应该满足,但是不满足也可以,相当于or
Occur.MUST_NOT:必须不满足。相当于not
(2) 使用queryparser查询
通过QueryParser也可以创建Query,QueryParser提供一个Parse方法,此方法可以直接根据查询语法来查询。Query对象执行的查询语法可通过System.out.println(query)查询,需要使用到分析器。建议创建索引时使用的分析器和查询索引时使用的分析器要一致。
① QueryParser
需要加入queryParser依赖的jar包。
【1】程序实现
@Test public void testQueryParser() throws Exception { IndexSearcher indexSearcher = getIndexSearcher(); //创建queryparser对象 //第一个参数默认搜索的域 //第二个参数就是分析器对象 QueryParser queryParser = new QueryParser("content", new IKAnalyzer()); Query query = queryParser.parse("Lucene是java开发的"); //执行查询 printResult(query, indexSearcher); }
【2】查询语法
1、基础的查询语法,关键词查询:
域名+“:”+搜索的关键字
例如:content:java
2、范围查询
域名+“:”+[最小值 TO 最大值]
例如:size:[1 TO 1000]
范围查询在lucene中支持数值类型,不支持字符串类型,在solr中支持字符串类型。
3、组合条件查询
1)+条件1 +条件2:两个条件之间是并且的关系and
例如:+filename:apache +content:apache
2)+条件1 条件2:必须满足第一个条件,应该满足第二个条件
例如:+filename:apache content:apache
3)条件1 条件2:两个条件满足其一即可。
例如:filename:apache content:apache
4)条件1 条件2:必须不满足条件1,要满足条件2
【3】MultiFieldQueryParser
可以指定多个默认搜索域
@Test public void testMultiFiledQueryParser() throws Exception { IndexSearcher indexSearcher = getIndexSearcher(); //可以指定默认搜索的域是多个 String[] fields = {"filename", "content"}; //创建一个MulitFiledQueryParser对象 MultiFieldQueryParser queryParser = new MultiFieldQueryParser(fields, new IKAnalyzer()); Query query = queryParser.parse("java AND apache"); System.out.println(query); //执行查询 printResult(query, indexSearcher); }
阅读全文
1 0
- Lucene 代码详解
- Lucene详解
- lucene详解
- Lucene 3.5 测试代码
- lucene实现分页代码
- Lucene建索引代码
- Lucene入门代码
- Lucene实例代码
- lucene搜索 代码示例
- lucene的代码示范
- lucene代码笔记1
- LUCENE Filed详解
- lucene.net 详解
- lucene索引过程详解
- lucene核心类详解
- lucene 3实例详解
- Lucene的索引详解
- lucene核心类详解
- Noip 2016 换教室
- centos 卸载python和yum之后的解决办法
- ABP官方文档(二十五)【数据传输对象验证】
- JSTL标签与EL表达式xaing
- Zookeeper之集群搭建-yellowcong
- Lucene 代码详解
- 完全理解 Python 迭代对象、迭代器、生成器
- 微信开发必备外网映射工具----Ngroke
- 【Caffe特征图可视化】【权重图weight】【特征图feat】
- 你不知道的CSS3选择器--精辟用法
- Android Chronometer类
- 4.3(4)
- jqgrid ajax加载
- linux 如何显示一个文件的某几行(中间几行)