lucene入门

布满荆棘的人生 2022-06-10 14:13 289阅读 0赞

Lucene是apache下的一个开放源代码的全文检索引擎工具包。提供了完整的查询引擎和索引引擎,部分文本分析引擎。Lucene的目的时为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索功能。

  1. Lucene实现全文检索的流程

Center

绿色表示索引过程,对要搜索的原始内容进行索引构建一个索引库,索引过程包括:确定原始内容即要搜索的内容—>采集文档-->创建文档-->分析文档-->索引文档

红色表示搜索过程,从索引库中搜索内容,搜索过程包括:用户通过搜索界面-->创建查询—>执行搜索,从索引库搜索—>渲染搜索结果

一、创建索引

1、获取原始文档

  1. 原始文档时指要索引和搜索的内容。原始内容包括互联网上的网页、数据库中的数据等。在Internet上采集信息的软件通常就称为爬虫或蜘蛛,信息采集工具lucene没有提供,需要自己编写或通过一些开源软件实现信息采集。

2、创建文档对象

  1. 在索引前需要将原始内容创建成文档(document),文档中包括一个一个的域(Field,相当于文件属性,如文件名,文件大小,文件内容,文件路径等),域中存储内容。每个document可以有多个Field,不同的document可以有不同的Field,同一个document可以有相同的Field(域名和域值相同)。每个文档都有一个唯一编号,就是文档id,我们不能更改。

3、分析文档

  1. 将原始内容创建为包含域(Field)的文档(document),需要再对域中的内容进行分析,分析的过程是经过对原始文档提取单词、将字母转为小写、去除标点符号、去除停用词等过程生成最终的语汇单元,可以将语汇单元理解为一个一个的单词。每个单词叫做一个termterm中包含两部分。一部分是文档的域名,另一部分是单词的内容。例如:文件名中包含的apache和文件内容中包含的apache是不同的term

4、创建索引

  1. 对所有文档分析得出的语汇单元进行索引,索引的目的时为了搜索,最终要实现只搜索被索引的语汇单元从而找到document(文档)。

创建索引是对语汇单元索引,通过词语找文档,这种索引的结构叫倒排索引结构。

二、在java中使用lucene

1、配置开发环境,导入jar包

Center 1

2、创建索引库代码

  1. public void test1() throws IOException {
  2. //第一步、创建IndexWriter对象
  3. /**
  4. * 1)创建indexWriter对象所需要的directory目录,用于指定索引库存放的位置
  5. * 2)创建官方推荐解析器,用于创建IndexWriterConfig对象
  6. * 3)创建IndexWriter对象需要的IndexWriterConfig对象
  7. * 4)创建IndexWriter对象
  8. */
  9. Directory directory = FSDirectory.open(new File("D:\\temp\\index"));
  10. Analyzer analyzer = new IKAnalyzer();
  11. IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_4_10_3, analyzer);//创建IndexWriterConfig对象时需要传入版本号和分词器
  12. IndexWriter index = new IndexWriter(directory, config);
  13. //第二步、创建Field对象,并将field对象添加到document对象中
  14. //获取文件夹对象,对文件夹下的文件进行遍历创建索引库
  15. File f = new File("D:\\searchsource");
  16. File[] listfiles = f.listFiles();
  17. for (File file : listfiles) {
  18. //第三步、创建document对象
  19. Document document = new Document();
  20. //文件名称
  21. String file_name = file.getName();
  22. Field fileNameField = new TextField("fileName", file_name, Store.YES);
  23. //文件大小
  24. long file_size = FileUtils.sizeOf(file);
  25. Field fileSizeField = new LongField("fileSize", file_size, Store.YES);
  26. //文件路径
  27. String file_path = file.getPath();
  28. Field filePathField = new StoredField("filePath", file_path);
  29. //文件内容
  30. String file_content = FileUtils.readFileToString(file);
  31. Field fileContentField = new TextField("fileContent", file_content,Store.NO);
  32. //将这些Field域存放到document对象中
  33. document.add(fileNameField);
  34. document.add(fileSizeField);
  35. document.add(filePathField);
  36. document.add(fileContentField);
  37. //第四步、使用indexwriter对象将document对象写入索引库,此过程进行索引创建。并将索引和document对象写入索引库
  38. index.addDocument(document);
  39. }
  40. //第五步、关闭IndexWriter对象
  41. index.close();
  42. }

关于field域的属性

是否分析:是否对域的内容进行分词处理。前提是我们要对域的内容进行查询。

是否索引:将Field分析后的词或整个Field值进行索引,只有索引方可搜索到。

比如:商品名称、商品简介分析后进行索引,订单号、身份证号不用分析但也要索引,这些将来都要作为查询条件。

是否存储:将Field值存储在文档中,存储在文档中的Field才可以从Document中获取

比如:商品名称、订单号,凡是将来要从Document中获取的Field都要存储。












































Field

数据类型

是否分析

是否索引

是否存储

说明

StringField(FieldName, FieldValue,Store.YES))

字符串

N

Y

YN

这个Field用来构建一个字符串Field,但是不会进行分析,会将整个串存储在索引中,比如(订单号,姓名等)

是否存储在文档中用Store.YESStore.NO决定

LongField(FieldName, FieldValue,Store.YES)

Long

Y

Y

YN

这个Field用来构建一个Long数字型Field,进行分析和索引,比如(价格)

是否存储在文档中用Store.YESStore.NO决定

StoredField(FieldName, FieldValue) 

重载方法,支持多种类型

N

N

Y

这个Field用来构建不同类型Field

不分析,不索引,但要Field存储在文档中

TextField(FieldName, FieldValue, Store.NO)

TextField(FieldName, reader)

 

字符串

Y

Y

YN

如果是一个Reader, lucene猜测内容比较多,会采用Unstored的策略.

使用Luke工具可以查看索引库中的详细信息

3、查询索引代码

  1. public void testIndexReader() throws IOException {
  2. // 第一步:创建一个Directory对象,也就是索引库存放的位置。
  3. Directory directory = FSDirectory.open(new File("D:\\temp\\index"));
  4. /* 索引库的位置如果在内存中
  5. Directory directory2 = new RAMDirectory();*/
  6. // 第二步:创建一个indexReader对象,需要指定Directory对象。
  7. IndexReader indexReader = DirectoryReader.open(directory);
  8. // 第三步:创建一个indexsearcher对象,需要指定IndexReader对象
  9. IndexSearcher searcher = new IndexSearcher(indexReader);
  10. // 第四步:创建一个TermQuery对象,指定查询的域和查询的关键词。
  11. Term term = new Term("fileName","全文检索");//指定term的域名和域值
  12. Query query = new TermQuery(term);
  13. // 第五步:执行查询。
  14. TopDocs topDocs = searcher.search(query,3);
  15. // 第六步:返回查询结果。遍历查询结果并输出。
  16. ScoreDoc[] scoreDocs = topDocs.scoreDocs;
  17. for (ScoreDoc scoreDoc : scoreDocs) {
  18. int doc = scoreDoc.doc; //获取文档id
  19. //获取文档对象
  20. Document document = indexReader.document(doc);
  21. //文件名
  22. String fileName = document.get("fileName");
  23. //文件大小
  24. String fileSize = document.get("fileSize");
  25. //文件路径
  26. String filePath = document.get("filePath");
  27. //文件内容
  28. String fileContent = document.get("fileContent");
  29. System.out.println(fileName+"...."+fileSize+"...."+filePath+"...."+fileContent);
  30. }
  31. // 第七步:关闭IndexReader对象
  32. indexReader.close();
  33. }

indexSearcher 搜索方法

indexSearcher.search(query, n):根据Query搜索,返回评分最高的n条记录

indexSearcher.search(query, filter, n):根据Query搜索,添加过滤策略,返回评分最高的n条记录

indexSearcher.search(query, n, sort):根据Query搜索,添加排序策略,返回评分最高的n条记录

indexSearcher.search(booleanQuery, filter, n, sort):根据Query搜索,添加过滤策略,添加排序策略,返回评分最高的n条记录

lucene默认使用的分词器对英文支持很好,对中文支持很差,所以需要使用第三方的分词器。这里使用IKAnalyzer

注意:搜索使用的分析器要和创建索引使用的分析器一致。

4、索引库的维护

1)删除全部索引

  1. public void test3() throws IOException {
  2. IndexWriter writer = getIndexWriter();
  3. writer.deleteAll();
  4. writer.close();
  5. }

2)按条件删除索引库内容

  1. public void test4() throws IOException {
  2. IndexWriter writer = getIndexWriter();
  3. Query query = new TermQuery(new Term("fileName","apache"));
  4. writer.deleteDocuments(query);
  5. writer.close();
  6. }

3)对索引库进行修改操作,原理就是先删除后添加。

  1. public void test5() throws IOException {
  2. IndexWriter writer = getIndexWriter();
  3. Document document = new Document();
  4. TextField text1 = new TextField("fileN","test1",Store.YES);
  5. TextField text2 = new TextField("fileC","test2",Store.YES);
  6. document.add(text1);
  7. document.add(text2);
  8. writer.updateDocument(new Term("fileName","lucene"),document,new IKAnalyzer());
  9. writer.close();
  10. }

5、索引库查询

1)、使用query的子类查询

** MatchAllDocsQuery 查询索引目录中的所有文档

  1. public void testMatchAllDocsQuery() throws Exception {
  2. IndexSearcher searcher = getIndexSearcher();
  3. Query query = new MatchAllDocsQuery();
  4. TopDocs topDocs = searcher.search(query, 10);
  5. ScoreDoc[] scoreDocs = topDocs.scoreDocs;
  6. for (ScoreDoc scoreDoc : scoreDocs) {
  7. int doc = scoreDoc.doc;
  8. Document document = searcher.getIndexReader().document(doc);
  9. String fileName = document.get("fileName");
  10. System.out.println(fileName);
  11. String filePath = document.get("filePath");
  12. System.out.println(filePath);
  13. String fileSize = document.get("fileSize");
  14. System.out.println(fileSize);
  15. String fileContent = document.get("fileContent");
  16. System.out.println(fileContent);
  17. System.out.println("--------------------");
  18. }
  19. searcher.getIndexReader().close();
  20. }

** TermQuery 指定要查询的域和要查询的关键词。

  1. Term term = new Term("fileName","全文检索");//指定term的域名和域值
  2. Query query = new TermQuery(term);

** NumericRangeQuery 根据数值范围查询

  1. public void test6() throws Exception {
  2. IndexSearcher searcher = getIndexSearcher();
  3. Query query = NumericRangeQuery.newLongRange("fileSize", 47L, 200L, false, true);
  4. printResult(searcher, query);
  5. }

这里根据文件大小范围进行查询,创建query对象时第一个参数是field域名,第二个参数是下边界值,第三个参数是上边界值,第四个是否包括这个最小值,第五个是否包括这个最大值。

** BooleanQuery 组合条件查询

  1. public void testBooleanQuery() throws Exception {
  2. IndexSearcher searcher = getIndexSearcher();
  3. BooleanQuery query = new BooleanQuery();
  4. Query query2 = new TermQuery(new Term("fileName","apache"));
  5. Query query3 = new TermQuery(new Term("fileName","lucene"));
  6. query.add(query2,Occur.SHOULD);
  7. query.add(query3,Occur.MUST);
  8. printResult(searcher, query);
  9. }

Occur.MUST:必须满足此条件,相当于and

Occur.SHOULD:应该满足,但是不满足也可以,相当于or

Occur.MUST_NOT:必须不满足。相当于not

2)、使用queryparser查询

语法 域名:域值

需要加入queryParser的jar包

  1. public void testQueryParser() throws Exception {
  2. //参数1、默认查询的域
  3. //参数2、采用的分析器
  4. QueryParser queryParse = new QueryParser("fileName", new IKAnalyzer());
  5. //MatchAllDocsQuery底层使用的就是*:*
  6. Query query = queryParse.parse("*:*");
  7. IndexSearcher searcher = getIndexSearcher();
  8. printResult(searcher, query);
  9. //关闭资源
  10. searcher.getIndexReader().close();
  11. }

通过QueryParser也可以创建Query,QueryParser提供一个Parse方法,此方法可以直接根据查询语法来查询。Query对象执行的查询语法可通过System.out.println(query);查询。

需要使用到分析器。建议创建索引时使用的分析器和查询索引时使用的分析器要一致。

查询语法

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

例如:-filename:apache content:apache
















Occur.MUST 查询条件必须满足,相当于and

+(加号)

Occur.SHOULD 查询条件可选,相当于or

 

空(不用符号)

Occur.MUST_NOT 查询条件不能满足,相当于not非

-(减号)

第二种写法:

条件1 AND 条件2

条件1 OR 条件2

条件1 NOT 条件2

MultiFieldQueryParser进行查询

MultiFieldQueryParser和QueryParser相比增加了默认的域是一个数组,也就是说可以有多个默认的域。(此功能比较鸡肋,可以直接使用QueryParser对象完成这样的功能)

  1. public void testMultiFieldQueryParser() throws Exception {
  2. //参数1、默认查询的域(数组)
  3. //参数2、采用的分析器
  4. String[] fields = {"fileName","fileContent"};
  5. MultiFieldQueryParser multiFieldQuery = new MultiFieldQueryParser(fields, new IKAnalyzer());
  6. Query query = multiFieldQuery.parse("java");
  7. IndexSearcher searcher = getIndexSearcher();
  8. printResult(searcher, query);
  9. //关闭资源
  10. searcher.getIndexReader().close();
  11. }

发表评论

表情:
评论列表 (有 0 条评论,289人围观)

还没有评论,来说两句吧...

相关阅读

    相关 lucene入门

    Lucene是apache下的一个开放源代码的全文检索引擎工具包。提供了完整的查询引擎和索引引擎,部分文本分析引擎。Lucene的目的时为软件开发人员提供一个简单易用的工具包,

    相关 Lucene入门

    > lucene 是一个全文检索引擎的架构,提供了一个简单却强大的应用程式接口,能够做全文索引和搜寻。 创建索引库 俩种储存方式: 第一种: //将索引存

    相关 Lucene的使用,Lucene入门

    本文主要介绍几个方面,为什么使用Lucene使用场景,解决的问题,Lucene的入门使用,以及Lucene一些语法(增删改查)。 一简述Lucene概念:磁盘上的一些邮件,文

    相关 lucene入门(三)

    前面两篇文章介绍了如何创建索引和搜索索引,理解了的话基本上就已经可以使用Lucene进行简单的全文检索了。学习完lucene之后,我个人有一个小小的demo,只是为了练习,在这