Create lucene index of the study notes

1 index Library Maintenance

In Section 4, we need to re-create the index, the index is to go to the library directory, manually deleted.

 

In the actual development, we may simply do not know where the library index, even if one knows, we can not always go manually delete, very troublesome! ! !

Therefore, we must learn how to maintain index database, use the program to operate the index database.

Note that the index is closely linked with the document, so the maintenance of the index, in fact, is to document the additions and deletions .

 

1.1 Add index (document)

1.1.1 Demand

The new database shelves of books, these books must also be added to the index database, or to not search the shelves of new books up.

 

1.1.2 code implementation

Call indexWriter.addDocument (doc) add indexes.

Create an index entry reference sample.

 

1.2 Delete Index (document)

1.2.1 Demand

Some books out of print sales, we need to remove the book from the library index.

1.2.2 code implementation

    @Test

    public void deleteIndex() throws Exception {

       // 1, the library directory specified index

       Directory directory = FSDirectory.open(new File("F:\\lucene\\0719"));

       2 // Create IndexWriterConfig

       IndexWriterConfig cfg = new IndexWriterConfig(Version.LATEST,

              new StandardAnalyzer());

       // 3. Create IndexWriter

       IndexWriter writer = new IndexWriter (directory, cfg);

       // 4, to delete the index by IndexWriter

       // delete the specified index

       writer.deleteDocuments(new Term("name", "apache"));

       // 5, closed IndexWriter

       writer.close();

      

       . System OUT .println ( "deleted successfully");

      

    }

1.2.3 Empty index Library

@Test

    public void deleteIndex() throws Exception {

       // 1, the library directory specified index

       Directory directory = FSDirectory.open(new File("F:\\lucene\\0719"));

       2 // Create IndexWriterConfig

       IndexWriterConfig cfg = new IndexWriterConfig(Version.LATEST,

              new StandardAnalyzer());

       // 3. Create IndexWriter

       IndexWriter writer = new IndexWriter (directory, cfg);

       // 4, to delete the index by IndexWriter

       // delete the specified index

       writer.deleteAll();

       // 5、关闭IndexWriter

       writer.close();

      

       System.out.println("清空索引库成功");

      

    }

 

1.3          更新索引(文档)

1.3.1        说明

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

1.3.2        代码实现

// 修改索引

    @Test

    public void updateIndex() throws Exception {

       // 1、指定索引库目录

       Directory directory = FSDirectory.open(new File("F:\\lucene\\0719"));

       // 2、创建IndexWriterConfig

       IndexWriterConfig cfg = new IndexWriterConfig(Version.LATEST,

              new StandardAnalyzer());

       // 3、 创建IndexWriter

       IndexWriter writer = new IndexWriter(directory, cfg);

       // 4、通过IndexWriter来修改索引

       // a)、创建修改后的文档对象

       Document document = new Document();

 

       // 文件名称

       Field filenameField = new StringField("name", "updateIndex", Store.YES);

       document.add(filenameField);

 

       // 修改指定索引为新的索引

       writer.updateDocument(new Term("name", "apache"), document);

 

       // 5、关闭IndexWriter

       writer.close();

      

       System.out.println("更新成功");

    }

 

2             搜索

问题:我们在入门示例中,已经知道Lucene是通过IndexSearcher对象,来执行搜索的。那我们为什么还要继续学习Lucene呢?

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

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

 

2.1          创建查询的两种方法

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

 

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

 

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

2.1.1        使用Lucene提供Query子类

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

 

使用TermQuery实例化

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

 

2.1.2        使用QueryParse解析查询表达式

       QueryParser会将用户输入的查询表达式解析成Query对象实例。如下代码:

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

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

 

2.2          常用的Query子类搜索

2.2.1        TermQuery

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

/**

     * Query子类查询之 TermQuery

     * 

     * 特点:不会再对查询的关键词做分词处理。

     *

     * 需要:查询书名与java教程相关书。

     */

@Test

    public void queryByTermQuery(){

       //1、获取一个查询对象

       Query query = new TermQuery(new Term("name", "编程思想"));

       doSearch(query);

      

    }

   private void doSearch(Query query) {

       try {

          

          

           //2、创建一个查询的执行对象

           //指定索引库的目录

           Directory d = FSDirectory.open(new File("F:\\lucene\\0719"));

           //创建流对象

           IndexReader reader = DirectoryReader.open(d);

           //创建搜索执行对象

           IndexSearcher searcher = new IndexSearcher(reader);

          

           //3、执行搜索

           TopDocs result = searcher.search(query, 10);

          

           //4、提出结果集,获取图书的信息

           int totalHits = result.totalHits;

           System.out.println("共查询到"+totalHits+"条满足条件的数据!");

           System.out.println("-----------------------------------------");

           //提取图书信息。

           //score即相关度。即搜索的关键词和 图书名称的相关度,用来做排序处理

           ScoreDoc[] scoreDocs = result.scoreDocs;

          

           for (ScoreDoc scoreDoc : scoreDocs) {

              /**

               * scoreDoc.doc的返回值,是文档的id, 即 将文档写入索引库的时候,lucene自动给这份文档做的一个编号。

               *

               * 获取到这个文档id之后,即可以根据这个id,找到这份文档。

               */

              int docId = scoreDoc.doc;

              System.out.println("文档在索引库中的编号:"+docId);

             

              //从文档中提取图书的信息

              Document doc = searcher.doc(docId);

               System.out.println("图书id:"+doc.get("id"));

              System.out.println("图书name:"+doc.get("name"));

              System.out.println("图书price:"+doc.get("price"));

              System.out.println("图书pic:"+doc.get("pic"));

              System.out.println("图书description:"+doc.get("description"));

              System.out.println();

              System.out.println("------------------------------------");

             

           }

          

           //关闭连接,释放资源

           if(null!=reader){

              reader.close();

           }

       } catch (Exception e) {

           e.printStackTrace();

       }

    }

 

2.2.2        NumericRangeQuery

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

/**

     * Query子类查询  之  NumricRangeQuery

     * 需求:查询所有价格在[60,80)之间的书

     * @param query

     */

@Test

    public void queryByNumricRangeQuery(){

        /**

         * 第一个参数:要搜索的域

         * 第二个参数:最小值

         * 第三个参数:最大值

         * 第四个参数:是否包含最小值

         * 第五个参数:是否包含最大值

         */

        Query query = NumericRangeQuery.newFloatRange("price", 60.0f, 80.0f, true, false);

       

        doSearch(query);

    }

 

2.2.3        BooleanQuery

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

/**

     * Query子类查询  之  BooelanQuery查询   组合条件查询

     *

     * 需求:查询书名包含java,并且价格区间在[60,80)之间的书。

     */

    @Test

    public void queryBooleanQuery(){

        //1、要使用BooelanQuery查询,首先要把单个创建出来,然后再通过BooelanQuery组合

        Query price = NumericRangeQuery.newFloatRange("price", 60.0f, 80.0f, true, false);

        Query name = new TermQuery(new Term("name", "java"));

       

        //2、创建BooleanQuery实例对象

        BooleanQuery query = new BooleanQuery();

        query.add(name, Occur.MUST_NOT);

        query.add(price, Occur.MUST);

        /**

         * MSUT  表示必须满足                          对应的是  +

         * MSUT_NOT  必须不满足                   应对的是  -

         * SHOULD  可以满足也可以不满足     没有符号

         *

         * SHOULD 与MUST、MUST_NOT组合的时候,SHOULD就没有意义了。

         */

       

        doSearch(query);

    }

 

2.3          通过QueryParser搜索

2.3.1        特点

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

2.3.2        语法

2.3.2.1     基础语法

域名:关键字

实例:name:java

 

2.3.2.2     组合条件语法

条件1 AND 条件2 

条件1 OR 条件2

条件1 NOT 条件2

 

2.3.3        QueryParser

2.3.3.1     代码实现

/**

     * 查询解析器查询  之  QueryParser查询

     */

@Test

    public void queryByQueryParser(){

       try {

          

           //1、加载分词器

           Analyzer analyzer = new StandardAnalyzer();

          

           /**

            * 2、创建查询解析器实例对象

            * 第一个参数:默认搜索的域。

            *          如果在搜索的时候,没有特别指定搜索的域,则按照默认的域进行搜索

            *          如何在搜索的时候指定搜索域呢?

            *          答:格式  域名:关键词        即   name:java教程

            *

            * 第二个参数:分词器   ,对关键词做分词处理

            */

           QueryParser parser = new QueryParser("description", analyzer);

          

           Query query = parser.parse("name:java教程");

          

           doSearch(query);

          

       } catch (Exception e) {

           e.printStackTrace();

       }

    }

 

2.3.4        MultiFieldQueryParser

通过MulitFieldQueryParse对多个域查询。

/**

     * 查询解析器查询  之  MultiFieldQueryParser查询

     * 

     *     特点:同时指定多个搜索域,并且对关键做分词处理

     */

    @Test

    public void queryByMultiFieldQueryParser(){

       try {

          

           //1、定义多个搜索的  name、description

           String[] fields = {"name","description"};

           //2、加载分词器

           Analyzer analyzer = new StandardAnalyzer();

          

           //3、创建 MultiFieldQueryParser实例对象

           MultiFieldQueryParser mParser = new MultiFieldQueryParser(fields, analyzer);

          

           Query query = mParser.parse("lucene教程");

          

           doSearch(query);

       } catch (Exception e) {

           e.printStackTrace();

       }

    }

 

3             中文分词器

3.1          什么是中文分词器

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

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

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

3.2          Lucene自带的中文分词器

3.2.1        StandardAnalyzer:

单字分词:就是按照中文一个字一个字地进行分词。如:“我爱中国”,
效果:“我”、“爱”、“中”、“国”。

3.2.2        CJKAnalyzer

二分法分词:按两个字进行切分。如:“我是中国人”,效果:“我是”、“是中”、“中国”“国人”。

 

上边两个分词器无法满足需求。

 

3.3          使用中文分词器IKAnalyzer

IKAnalyzer继承Lucene的Analyzer抽象类,使用IKAnalyzer和Lucene自带的分析器方法一样,将Analyzer测试代码改为IKAnalyzer测试中文分词效果。

 

如果使用中文分词器ik-analyzer,就在索引和搜索程序中使用一致的分词器ik-analyzer。

3.3.1        使用luke测试IK中文分词

(1)打开Luke,不要指定Lucene目录。否则看不到效果

(2)在分词器栏,手动输入IkAnalyzer的全路径

org.wltea.analyzer.lucene.IKAnalyzer

 

 

3.3.2        改造代码,使用IkAnalyzer做分词器

3.3.2.1     添加jar包

 

 

3.3.2.2     修改分词器代码

// 创建中文分词器

Analyzer analyzer = new IKAnalyzer();

 

3.3.2.3     扩展中文词库

拓展词库的作用:在分词的过程中,保留定义的这些词

1在src或其他source目录下建立自己的拓展词库,mydict.dic文件,例如:

 

 

2在src或其他source目录下建立自己的停用词库,ext_stopword.dic文件

停用词的作用:在分词的过程中,分词器会忽略这些词。

3在src或其他source目录下建立IKAnalyzer.cfg.xml,内容如下(注意路径对应):

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> 

<properties> 

    <comment>IK Analyzer 扩展配置</comment>

    <!-- 用户可以在这里配置自己的扩展字典 -->

     <entry key="ext_dict">mydict.dic</entry>

     <!-- 用户可以在这里配置自己的扩展停用词字典    -->

    <entry key="ext_stopwords">ext_stopword.dic</entry>

</properties>

 

 

如果想配置扩展词和停用词,就创建扩展词的文件和停用词的文件,文件的编码要是utf-8。

注意:不要用记事本保存扩展词文件和停用词文件,那样的话,格式中是含有bom

 

Guess you like

Origin www.cnblogs.com/w410782823/p/11209730.html