Lucene 入门 06 - 索引库的维护

咩是索引库的维护 ?
再来一个大白话: 就是针对创好的索引库进行增删改查. 够不够直白.

在前几章说过了创建索引库, 但是在创建 Field 的时候, 使用的都是 TextField.
其实 Field 也是分好多属性的.

Field 域的属性

  1. 是否需要进行分词

    • 前提是这个字段首先要创建索引。然后如果这个字段的值是不可分割的,那么就不需要分词。例如:ID
  2. 是否需要创建索引

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

    • 将 Field 值存储在文档中, 存储在文档中的 Field 才可以从 Document 中获取.比如:商品名称, 订单号, 凡是将来要从 Document 中获取的 Field 都要存储.
    • 这个简单来说, 只要是一个字段最终要显示到结果中的, 那么就一定要存储. 否则不存储.

1. Field 域的类型

在创建域的时候, 根据实际的数据类型, 来选择域的类型进行创建

Field 类 数据类型 Analyzed 是否分析 Indexed 是否索引 Stored 是否存储 说明
String Field(FieldName, FieldValue , Store.YES) 字符串 N Y Y 或N 这个Field 用来构建一个字符串Field, 但是不会进行分析, 会将整个字符串存储在索引中. 比如(订单号, 姓名等). 是否存储在文档中用 Store.YES / Store.NO决定
LongPoint(String name, long point),intPoint ...... Long 型 Y Y N 可以使用 LongPoint, IntPoint 等类型存储数值类型的数据, 让数值类型可以进行索引. 但是不能存储数据, 如果想存储数据还需要使用 StoreField
StoreField(FieldName, FieldValue) 重载方法, 支持多种类型 N N Y 这个 Field 用来构建不同类型的 Field, 不拆分,不索引, 但要 Field 存储在文档中, 比如路径等信息.
TextField(FieldName, FieldValue, Store.NO) 或
TextFiled(FieldName, reader)
字符串 或流 Y Y Y 或 N 如果是一个 Reader, Lucene猜测内容比较多, 会采用 Unstored 的策略

2. 代码改造.

现在我们知道了域的属性后, 对最开始我们的索引库创建进行代码改造.
Lucene 入门 03 - 全文检索创建的代码实现

  • 路径 "path" 我们只需要存储就行了,不需要分析, 所以要换成 StoreField.
  • 文件大小"size" 我们不需要进行存储, 但是我们可能又需要计算例如按大小来过滤. 那么使用 LongPoint 来分析并添加索引,但不存储, 使用 StoredField 来存储.

改造后代码如下:

    @Test
    public void createIndex() throws Exception {
        //1.创建一个 Director 对象, 指定索引库保存的位置.把索引保存在磁盘
        Directory mDirectory = FSDirectory.open(new File("/Users/yzhang/Desktop/Director").toPath());
        //2. 创建一个 IndexWriter 对象
        //不再使用默认的分析器, 使用 IK
        IndexWriterConfig indexWriterConfig = new IndexWriterConfig(new IKAnalyzer());
        IndexWriter indexWriter = new IndexWriter(mDirectory, indexWriterConfig);

        //读取磁盘上的文件 (我磁盘上放了几个 text)
        File dir = new File("/Users/yzhang/Desktop/searchsource");
        File[] files = dir.listFiles();
        for (File file : files) {
            String fileName = file.getName();
            String filePath = file.getPath();
            String fileContent = FileUtils.readFileToString(file, "utf-8");
            long fileSize = FileUtils.sizeOf(file);
            //3. 创建域
            //args1: 域的名称. args2: 域的内容. args3:是否存储到磁盘
            Field fieldName = new TextField("name", fileName, Field.Store.YES); 
            //变为 StoreField         
            Field fieldPath = new StoredField("path", filePath);
            Field fieldContent = new TextField("content", fileContent, Field.Store.YES);
            //使用 LongPoint 进行分析和索引
            Field fieldSizeValue = new LongPoint("size", fileSize);
            //使用 StoreField 进行存储
            Field fieldSizeStore = new StoredField("size", fileSize);

            //对每个文件创建文本对象.
            Document document = new Document();
            ///4. 像文档中添加域
            document.add(fieldName);
            document.add(fieldPath);
            document.add(fieldContent);
            //添加的时候也要把这两个都添加进去
            document.add(fieldSizeValue);
            document.add(fieldSizeStore);
            //5. 把文档对象写入索引库
            indexWriter.addDocument(document);
        }
        //6. 关闭 indexwriter
        indexWriter.close(); 
    }

3. 索引库的增加

添加索引到已存在的索引库

//添加索引
@Test
public void addDocument() throws Exception {
    //索引库存放路径
    Directory directory = FSDirectory.open(new File("/Users/yzhang/Desktop/Director").toPath());
    IndexWriterConfig config = new IndexWriterConfig(new IKAnalyzer());
    //创建一个indexwriter对象
    IndexWriter indexWriter = new IndexWriter(directory, config);
    //创建一个Document对象
    Document document = new Document();
    //向document对象中添加域。
    //不同的document可以有不同的域,同一个document可以有相同的域。
    document.add(new TextField("filename", "新添加的文档", Field.Store.YES));
    document.add(new TextField("content", "新添加的文档的内容", Field.Store.NO));
    //LongPoint创建索引
    document.add(new LongPoint("size", 1000l));
    //StoreField存储数据
    document.add(new StoredField("size", 1000l));
    //不需要创建索引的就使用StoreField存储
    document.add(new StoredField("path", "d:/temp/1.txt"));
    //添加文档到索引库
    indexWriter.addDocument(document);
    //关闭indexwriter
    indexWriter.close();
}

4. 索引库的删除

删除全部
将索引目录的索引信息全部删除,直接彻底删除,无法恢复, 慎用.

    @Test
    public void deleteAllDocument() throws Exception 
        //索引库存放路径
        Directory directory = FSDirectory.open(new File("/Users/yzhang/Desktop/Director").toPath());
        IndexWriterConfig config = new IndexWriterConfig(new IKAnalyzer());
        //创建一个indexwriter对象
        IndexWriter indexWriter = new IndexWriter(directory, config);
        indexWriter.deleteAll();
        indexWriter.close();
    }

指定查询条件删除
例如: 删除域名为 name 中,关键词为 apache 的文档

    @Test
    public void deleteDocument() throws Exception 
        //索引库存放路径
        Directory directory = FSDirectory.open(new File("/Users/yzhang/Desktop/Director").toPath());
        IndexWriterConfig config = new IndexWriterConfig(new IKAnalyzer());
        //创建一个indexwriter对象
        IndexWriter indexWriter = new IndexWriter(directory, config);
        indexWriter.deleteDocuments(new Term("name","apache"));
        indexWriter.close();
    }

5. 索引库的修改

  • 索引库修改的原理就是先删除再新增一个.
  • 修改功能会根据 Term 进行匹配, 所有匹配到的都会被删除. 例如订单 ID,证件号等. 所以我们一般修改的时候, 都会根据一个唯一不重复的字段进行匹配修改. 但是使用 Term ,要求值必须是字符串, 如果不是,则无法使用 Term.
    @Test
    public void updateIndex() throws Exception 
        //索引库存放路径
        Directory directory = FSDirectory.open(new File("/Users/yzhang/Desktop/Director").toPath());
        IndexWriterConfig config = new IndexWriterConfig(new IKAnalyzer());
        //创建一个indexwriter对象
        IndexWriter indexWriter = new IndexWriter(directory, config);
        //创建一个Document对象
        Document document = new Document();
        document.add(new StringField("name", "zz",Field.Store.YES));
        document.add(new TextField("name", "zz1",Field.Store.YES));
        document.add(new TextField("name", "zz2",Field.Store.YES));

        //更新name 域中 值为 spring 的文档,为新的 Document
        indexWriter.updateDocument(new Term("name","spring"), document);
        indexWriter.close();
    }

下一章重点学习一下查询, Lucene 的查询是很重要的. 所以单独用一个章节来学习.

你可能感兴趣的:(Lucene 入门 06 - 索引库的维护)