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


    删除索引(文档)

    需求

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

     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读取内容。

  • 相关阅读:
    Python学习笔记:pd.drop删除行或列
    Python学习笔记:pd.droplevel删除指定级别索引、列名
    Python学习笔记:pd.date_range构造时间序列
    yum安装时提示app is currently holding the yum lock; waiting for it to exit
    Mysql模糊查询like效率,以及更高效的写法
    解决css文件返回格式Content-Type为text/html问题
    4 20210412-1 原型设计作业
    第八周课程总结
    第六周&java实验报告四
    第四周总结
  • 原文地址:https://www.cnblogs.com/vieta/p/11209565.html
Copyright © 2020-2023  润新知