Lucene索引库维护、搜索、中文分词器

2019/07/18 19:40
阅读数 154

删除索引(文档)

需求

某些图书不再出版销售了,我们需要从索引库中移除该图书。

 1 @Test
 2     public void deleteIndex() throws Exception {
 3         // 1、指定索引库目录
 4         Directory directory = FSDirectory.open(new File("F:\\lucene\\0719"));
 5         // 2、创建IndexWriterConfig
 6         IndexWriterConfig cfg = new IndexWriterConfig(Version.LATEST,
 7                 new StandardAnalyzer());
 8         // 3、 创建IndexWriter
 9         IndexWriter writer = new IndexWriter(directory, cfg);
10         // 4、通过IndexWriter来删除索引
11         // 删除指定索引
12         writer.deleteDocuments(new Term("name", "apache"));
13         // 5、关闭IndexWriter
14         writer.close();
15         
16         System.out.println("删除成功");
17         
18     }
View Code

清空索引库

 1 @Test
 2     public void deleteIndex() throws Exception {
 3         // 1、指定索引库目录
 4         Directory directory = FSDirectory.open(new File("F:\\lucene\\0719"));
 5         // 2、创建IndexWriterConfig
 6         IndexWriterConfig cfg = new IndexWriterConfig(Version.LATEST,
 7                 new StandardAnalyzer());
 8         // 3、 创建IndexWriter
 9         IndexWriter writer = new IndexWriter(directory, cfg);
10         // 4、通过IndexWriter来删除索引
11         // 删除指定索引
12         writer.deleteAll();
13         // 5、关闭IndexWriter
14         writer.close();
15         
16         System.out.println("清空索引库成功");
17         
18     }
View Code

更新索引(文档)

Lucene更新索引比较特殊,是先删除满足条件的索引,再添加新的索引。

 1 @Test
 2     public void updateIndex() throws Exception {
 3         // 1、指定索引库目录
 4         Directory directory = FSDirectory.open(new File("F:\\lucene\\0719"));
 5         // 2、创建IndexWriterConfig
 6         IndexWriterConfig cfg = new IndexWriterConfig(Version.LATEST,
 7                 new StandardAnalyzer());
 8         // 3、 创建IndexWriter
 9         IndexWriter writer = new IndexWriter(directory, cfg);
10         // 4、通过IndexWriter来修改索引
11         // a)、创建修改后的文档对象
12         Document document = new Document();
13 
14         // 文件名称
15         Field filenameField = new StringField("name", "updateIndex", Store.YES);
16         document.add(filenameField);
17 
18         // 修改指定索引为新的索引
19         writer.updateDocument(new Term("name", "apache"), document);
20 
21         // 5、关闭IndexWriter
22         writer.close();
23         
24         System.out.println("更新成功");
25     }
View Code

已经知道Lucene是通过IndexSearcher对象,来执行搜索的。那我们为什么还要继续学习Lucene呢?

答:因为在实际的开发中,我们的查询的业务是相对复杂的,比如我们在通过关键词查找的时候,往往进行价格、商品类别的过滤。

而Lucene提供了一套查询方案,供我们实现复杂的查询。

-------------------------------------------------------------------------------------------------------------------------------

 创建查询的两种方法

执行查询之前,必须创建一个查询Query查询对象。

 

Query自身是一个抽象类,不能实例化,必须通过其它的方式来实现初始化。

 

在这里,Lucene提供了两种初始化Query查询对象的方式。

 

 使用Lucene提供Query子类

Query是一个抽象类,lucene提供了很多查询对象,比如TermQuery项精确查询,NumericRangeQuery数字范围查询等。

 

使用TermQuery实例化

Query query = new TermQuery(new Term("name", "lucene"));

使用QueryParse解析查询表达式

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

Query query = queryParser.parse("name:lucene");

常用的Query子类搜索

TermQuery

特点:查询的关键词不会再做分词处理,作为整体来搜索。代码如下:

 1 /**
 2      * Query子类查询之 TermQuery
 3      *  
 4      * 特点:不会再对查询的关键词做分词处理。
 5      * 
 6      * 需要:查询书名与java教程相关书。
 7      */
 8 @Test
 9     public void queryByTermQuery(){
10         //1、获取一个查询对象
11         Query query = new TermQuery(new Term("name", "编程思想"));
12         doSearch(query);
13         
14     }
15    private void doSearch(Query query) {
16         try {
17             
18             
19             //2、创建一个查询的执行对象
20             //指定索引库的目录
21             Directory d = FSDirectory.open(new File("F:\\lucene\\0719"));
22             //创建流对象
23             IndexReader reader = DirectoryReader.open(d);
24             //创建搜索执行对象
25             IndexSearcher searcher = new IndexSearcher(reader);
26             
27             //3、执行搜索
28             TopDocs result = searcher.search(query, 10);
29             
30             //4、提出结果集,获取图书的信息
31             int totalHits = result.totalHits;
32             System.out.println("共查询到"+totalHits+"条满足条件的数据!");
33             System.out.println("-----------------------------------------");
34             //提取图书信息。
35             //score即相关度。即搜索的关键词和 图书名称的相关度,用来做排序处理
36             ScoreDoc[] scoreDocs = result.scoreDocs;
37             
38             for (ScoreDoc scoreDoc : scoreDocs) {
39                 /**
40                  * scoreDoc.doc的返回值,是文档的id, 即 将文档写入索引库的时候,lucene自动给这份文档做的一个编号。
41                  * 
42                  * 获取到这个文档id之后,即可以根据这个id,找到这份文档。
43                  */
44                 int docId = scoreDoc.doc;
45                 System.out.println("文档在索引库中的编号:"+docId);
46                 
47                 //从文档中提取图书的信息
48                 Document doc = searcher.doc(docId);
49                 System.out.println("图书id:"+doc.get("id"));
50                 System.out.println("图书name:"+doc.get("name"));
51                 System.out.println("图书price:"+doc.get("price"));
52                 System.out.println("图书pic:"+doc.get("pic"));
53                 System.out.println("图书description:"+doc.get("description"));
54                 System.out.println();
55                 System.out.println("------------------------------------");
56                 
57             }
58             
59             //关闭连接,释放资源
60             if(null!=reader){
61                 reader.close();
62             }
63         } catch (Exception e) {
64             e.printStackTrace();
65         }
66     }
View Code

 NumericRangeQuery

指定数字范围查询.(创建field类型时,注意与之对应)

 1 /**
 2      * Query子类查询  之  NumricRangeQuery
 3      * 需求:查询所有价格在[60,80)之间的书
 4      * @param query
 5      */
 6 @Test
 7     public void queryByNumricRangeQuery(){
 8         /**
 9          * 第一个参数:要搜索的域
10          * 第二个参数:最小值
11          * 第三个参数:最大值
12          * 第四个参数:是否包含最小值
13          * 第五个参数:是否包含最大值
14          */
15         Query query = NumericRangeQuery.newFloatRange("price", 60.0f, 80.0f, true, false);
16         
17         doSearch(query);
18     }
View Code

 BooleanQuery

BooleanQuery,布尔查询,实现组合条件查询。

 1 /**
 2      * Query子类查询  之  BooelanQuery查询   组合条件查询
 3      * 
 4      * 需求:查询书名包含java,并且价格区间在[60,80)之间的书。
 5      */
 6     @Test
 7     public void queryBooleanQuery(){
 8         //1、要使用BooelanQuery查询,首先要把单个创建出来,然后再通过BooelanQuery组合
 9         Query price = NumericRangeQuery.newFloatRange("price", 60.0f, 80.0f, true, false);
10         Query name = new TermQuery(new Term("name", "java"));
11         
12         //2、创建BooleanQuery实例对象
13         BooleanQuery query = new BooleanQuery();
14         query.add(name, Occur.MUST_NOT);
15         query.add(price, Occur.MUST);
16         /**
17          * MSUT  表示必须满足                          对应的是  +
18          * MSUT_NOT  必须不满足                   应对的是  -
19          * SHOULD  可以满足也可以不满足     没有符号
20          * 
21          * SHOULD 与MUST、MUST_NOT组合的时候,SHOULD就没有意义了。
22          */
23         
24         doSearch(query);
25     }
View Code

通过QueryParser搜索

  特点

对搜索的关键词,做分词处理。

  语法

  基础语法

域名:关键字

实例:name:java

 

   组合条件语法

条件1 AND 条件2 

条件1 OR 条件2

条件1 NOT 条件2

 

QueryParser

 1 /**
 2      * 查询解析器查询  之  QueryParser查询
 3      */
 4 @Test
 5     public void queryByQueryParser(){
 6         try {
 7             
 8             //1、加载分词器
 9             Analyzer analyzer = new StandardAnalyzer();
10             
11             /**
12              * 2、创建查询解析器实例对象
13              * 第一个参数:默认搜索的域。
14              *          如果在搜索的时候,没有特别指定搜索的域,则按照默认的域进行搜索
15              *          如何在搜索的时候指定搜索域呢?
16              *          答:格式  域名:关键词        即   name:java教程
17              * 
18              * 第二个参数:分词器   ,对关键词做分词处理
19              */
20             QueryParser parser = new QueryParser("description", analyzer);
21             
22             Query query = parser.parse("name:java教程");
23             
24             doSearch(query);
25             
26         } catch (Exception e) {
27             e.printStackTrace();
28         }
29     }
View Code

MultiFieldQueryParser

通过MulitFieldQueryParse对多个域查询。

 1 /**
 2      * 查询解析器查询  之  MultiFieldQueryParser查询
 3      *  
 4      *     特点:同时指定多个搜索域,并且对关键做分词处理
 5      */
 6     @Test
 7     public void queryByMultiFieldQueryParser(){
 8         try {
 9             
10             //1、定义多个搜索的  name、description
11             String[] fields = {"name","description"};
12             //2、加载分词器
13             Analyzer analyzer = new StandardAnalyzer();
14             
15             //3、创建 MultiFieldQueryParser实例对象
16             MultiFieldQueryParser mParser = new MultiFieldQueryParser(fields, analyzer);
17             
18             Query query = mParser.parse("lucene教程");
19             
20             doSearch(query);
21         } catch (Exception e) {
22             e.printStackTrace();
23         }
24     }
View Code

中文分词器

什么是中文分词器

学过英文的都知道,英文是以单词为单位的,单词与单词之间以空格或者逗号句号隔开

而中文的语义比较特殊,很难像英文那样,一个汉字一个汉字来划分。

所以需要一个能自动识别中文语义的分词器

 

 使用中文分词器IKAnalyzer

 

添加jar包

修改分词器代码

1 / 创建中文分词器
2 Analyzer analyzer = new IKAnalyzer();

 

 

 

思考?

在一堆文件中,如何快速根据关键词找出对应的文件?

 

思路:(1)使用全文检索来解决问题

         (2)数据源由数据库变成一堆文件。

         (3)从一堆文件中,读出里面的内容,转成文档,创建索引库。

         (4)创建索引库之后,再根据关键词搜索索引库,找出文件的名称。

 

问题:如何读文件的内容?

答:txt文本,直接使用IO即可。

        doc|docx  使用POI读取内容。

 

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部