Java全文检索Lucene急速入门知识

Posted 三更编程菌

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java全文检索Lucene急速入门知识相关的知识,希望对你有一定的参考价值。


1、流程分析

Java全文检索Lucene急速入门知识

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

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

2、生成索引看库

2.1、获得原始文档

原始文档,简单地说就是我们准备搜索的内容。可以是互联网上的网页、数据库中的数据、磁盘上的文件等。

2.2、创建文档对象

在创建索引前,我们需要将原始内容创建成文档(Document),一个文档中会包括很多的的域(Field),然后在域中存储原始文档的一些内容。 每一个文件可以当成一个document,Document下面可以包含多个Field(域),域由两部分组成:域的名称和值,可以理解为以key和value的形式存放数据。其实还有一个类型,用来表示域中存放数据的类型,这个不用我们考虑,可以在调用方法时作区分。比如我们现在以磁盘上面的文件为例,那么每个文件下可以包含四个域:name(名称)、path(路径)、context(内容)、size(文件大小)。如下所示:

名称
name Helloworld.java
path f://Helloworld.java
context public class HelloWorld...
size 4562

注意:每个文档都有一个唯一的编号,就是文档id。

Field域还有三个属性,如下所示:

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

  • 是否索引:将Field分析后的词或整个Field值进行索引,只有索引的内容才能搜索到。比如:商品名称、商品简介分析后进行索引,订单号、身份证号不用分析但也要索引,这些将来都要作为查询条件。

  • 是否存储:将Field值存储在文档中,存储在文档中的Field才可以从Document中获取比如:商品名称、订单号,凡是将来要从Document中获取的Field都要存储。

总结下来就是,是否查询这些内容决定了是否进行分析,时候进行搜索决定了是否索引,是否眼展示内容决定了是否进行存储。

附上一张表,用来展示各个方法对这三个属性的条件。


2.3、分析文档

说白了这就是一个分词的操作,就是挑选出关键词,去除没用的。比如根据空格进行字符串的拆分得到关键词列表、将关键词中的字母转为小写、去除标点符号、去除停用词(即需要过滤掉的词汇)等。

原文档内容:Lucene is a Java full-text search engine. Lucene is not a complete application, but rather a code library and API that can easily be used to add search capabilities to applications.

分析后得到的语汇单元:lucene、java、full、search、engine。。。。

分析得到的每个关键词封装成一个Term对象,Term中包含两部分:一部分是关键词所在的域名,另一部分是关键词的内容。不同的域中拆分出来的相同的关键词是不同的term。

2.4、创建索引

说了那么多,我们先进行导包操作,需要导入下面这些包,按照从左往右的顺序依次为:文件输入输出、汉语词法分析、Lucene包。

     
       
       
     
  1. commons-ioIK-Analyzer-1.0-SNAPSHOTlucene-analyzers-common-7.4.0lucene-core-7.4.0lucene-queryparser-7.4.0

接着来看一下创建索引的方法:

     
       
       
     
  1. public void createIndex() throws Exception {

  2. //1、创建一个Director对象,指定索引库保存的位置。

  3. //把索引库保存在内存中

  4. //Directory directory = new RAMDirectory();

  5. //把索引库保存在磁盘

  6. Directory directory = FSDirectory.open(new File("F:\\index").toPath());

  7. //2、基于Directory对象创建一个IndexWriter对象

  8. IndexWriterConfig config = new IndexWriterConfig(new IKAnalyzer());

  9. IndexWriter indexWriter = new IndexWriter(directory, config);

  10. //3、读取磁盘上的文件,对应每个文件创建一个文档对象。

  11. File dir = new File("F:\\texts");

  12. File[] files = dir.listFiles();

  13. for (File f : files) {

  14. //取文件名

  15. String fileName = f.getName();

  16. //文件的路径

  17. String filePath = f.getPath();

  18. //文件的内容

  19. String fileContent = FileUtils.readFileToString(f, "utf-8");

  20. //文件的大小

  21. long fileSize = FileUtils.sizeOf(f);

  22. //创建Field

  23. //参数1:域的名称,参数2:域的内容,参数3:是否存储

  24. Field fieldName = new TextField("name", fileName, Field.Store.YES);

  25. Field fieldPath = new StoredField("path", filePath);

  26. Field fieldContent = new TextField("content", fileContent, Field.Store.YES);

  27. Field fieldSizeValue = new LongPoint("size", fileSize);

  28. Field fieldSizeStore = new StoredField("size", fileSize);

  29. //创建文档对象

  30. Document document = new Document();

  31. //向文档对象中添加域

  32. document.add(fieldName);

  33. document.add(fieldPath);

  34. document.add(fieldContent);

  35. //document.add(fieldSize);

  36. document.add(fieldSizeValue);

  37. document.add(fieldSizeStore);

  38. //5、把文档对象写入索引库

  39. indexWriter.addDocument(document);

  40. }

  41. //6、关闭indexwriter对象

  42. indexWriter.close();

  43. }


3、查询索引

3.1、关键词查询

代码实现上上面几乎相同,最基本就是根据关键词查询内容,如下所示:

     
       
       
     
  1. public void searchIndex() throws Exception {

  2. //1、创建一个Director对象,指定索引库的位置

  3. Directory directory = FSDirectory.open(new File("F:\\index").toPath());

  4. //2、创建一个IndexReader对象

  5. IndexReader indexReader = DirectoryReader.open(directory);

  6. //3、创建一个IndexSearcher对象,构造方法中的参数indexReader对象。

  7. IndexSearcher indexSearcher = new IndexSearcher(indexReader);

  8. //4、创建一个Query对象,TermQuery

  9. Query query = new TermQuery(new Term("name", "spring"));

  10. //5、执行查询,得到一个TopDocs对象

  11. //参数1:查询对象 参数2:查询结果返回的最大记录数

  12. TopDocs topDocs = indexSearcher.search(query, 10);

  13. //6、取查询结果的总记录数

  14. System.out.println("查询总记录数:" + topDocs.totalHits);

  15. //7、取文档列表

  16. ScoreDoc[] scoreDocs = topDocs.scoreDocs;

  17. //8、打印文档中的内容

  18. for (ScoreDoc doc :

  19. scoreDocs) {

  20. //取文档id

  21. int docId = doc.doc;

  22. //根据id取文档对象

  23. Document document = indexSearcher.doc(docId);

  24. System.out.println(document.get("name"));

  25. System.out.println(document.get("path"));

  26. System.out.println(document.get("size"));

  27. }

  28. //9、关闭IndexReader对象

  29. indexReader.close();

  30. }

3.2、语句查询

当然我们也可以用文本,例如一句话去查询,去查询哪些文件里面包含这句话。那么代码该怎么操作呢?

     
       
       
     
  1. private void printResult(Query query) throws Exception {

  2. IndexReader indexReader =

  3. DirectoryReader.open(FSDirectory.open(new File("F:\\index").toPath()));

  4. IndexSearcher indexSearcher = new IndexSearcher(indexReader);

  5. //创建一个QueryPaser对象,两个参数。参数1:默认搜索域,参数2:分析器对象

  6. QueryParser queryParser = new QueryParser("name", new IKAnalyzer());

  7. //使用QueryPaser对象创建一个Query对象

  8. Query query = queryParser.parse("lucene是一个Java开发的全文检索工具包");

  9. //执行查询,查询出10条数据

  10. TopDocs topDocs = indexSearcher.search(query, 10);

  11. System.out.println("总记录数:" + topDocs.totalHits);

  12. ScoreDoc[] scoreDocs = topDocs.scoreDocs;

  13. for (ScoreDoc doc:scoreDocs){

  14. //取文档id

  15. int docId = doc.doc;

  16. //根据id取文档对象

  17. Document document = indexSearcher.doc(docId);

  18. System.out.println(document.get("name"));

  19. System.out.println(document.get("path"));

  20. System.out.println(document.get("size"));

  21. }

  22. indexReader.close();

  23. }

3.1、范围查询

我们也可以根据范围进行查询,如下所示:

     
       
       
     
  1. //创建一个Query对象,查询size的范围,最小值01,最大值1001

  2. Query query = LongPoint.newRangeQuery("size", 0l, 100l);

  3. printResult(query);

4、维护索引

4.1、添加索引

     
       
       
     
  1. public void addDocument() throws Exception {

  2. //创建一个IndexWriter对象,需要使用IKAnalyzer作为分析器

  3. IndexWriter indexWriter =

  4. new IndexWriter(FSDirectory.open(new File("F:\\index").toPath()),

  5. new IndexWriterConfig(new IKAnalyzer()));

  6. //创建一个Document对象

  7. Document document = new Document();

  8. //向document对象中添加域

  9. document.add(new TextField("name", "新添加的文件", Field.Store.YES));

  10. document.add(new TextField("content", "新添加的文件内容", Field.Store.NO));

  11. document.add(new StoredField("path", "新添加的文件路径"));

  12. // 把文档写入索引库

  13. indexWriter.addDocument(document);

  14. //关闭索引库

  15. indexWriter.close();

  16. }

4.2、删除索引

     
       
       
     
  1. public void deleteAllDocument() throws Exception {

  2. //删除全部文档

  3. indexWriter.deleteAll();

  4. //关闭索引库

  5. indexWriter.close();

  6. }

  7. //根据条件删除索引

  8. public void deleteDocumentByQuery() throws Exception {

  9. indexWriter.deleteDocuments(new Term("name", "apache"));

  10. indexWriter.close();

  11. }

4.3、更新索引

原理就是先删除后添加。

     
       
       
     
  1. public void updateDocument() throws Exception {

  2. //创建一个新的文档对象

  3. Document document = new Document();

  4. //向文档对象中添加域

  5. document.add(new TextField("name", "更新之后的文档", Field.Store.YES));

  6. document.add(new TextField("name1", "更新之后的文档2", Field.Store.YES));

  7. document.add(new TextField("name2", "更新之后的文档3", Field.Store.YES));

  8. //更新操作,要删除的对象

  9. indexWriter.updateDocument(new Term("name", "spring"), document);

  10. //关闭索引库

  11. indexWriter.close();

  12. }


讲了这么多,大家是不是感觉很流弊的样子,但是要告诉大家一点,实际开发过程中,一般不会使用Lucene进行开发,我们会选择Elasticsearch之类的检索引擎,这个底层也是Lucene实现的,大家可以先了解一下Lucene,后面我们再聊一下ES~

纯干货

零水分

三更编程菌

我在这里等你哟!

以上是关于Java全文检索Lucene急速入门知识的主要内容,如果未能解决你的问题,请参考以下文章

LuceneApache Lucene全文检索引擎架构之入门实战1

Lucene 入门实例

《Lucene由潜入深教程系列》之Lucene入门实例

全文检索:Apache Lucene框架入门实例

原创Lucene001--介绍和入门

全文检索工具Lucene入门教程