Lucene中的域类型及文档的更新/删除

Field域

Field是文档中的域,包括Field名和Field值两部分,一个文档可以包括多个Field,Document只是Field的一个承载体,Field值即为要索引的内容,也是要搜索的内容。

Field属性

是否分词 (tokenized)

  • 是:作分词处理,即将Field值进行分词,分词的目的是为了索引。

比如:商品名称、商品描述等,这些内容用户要输入关键字搜索,由于搜索的内容格式大、内容多需要分词后将语汇单元建立索引

  • 否:不作分词处理

比如:商品id、订单号、身份证号等

是否索引 (indexed)

  • 是:进行索引。将Field分词后的词或整个Field值进行索引,存储到索引域,索引的目的是为了搜索。

比如:商品名称、商品描述分析后进行索引,订单号、身份证号不用分词但也要索引,这些将来都要作为查询条件。

  • 否:不索引。如果不需要索引就不需要分词。

比如:图片路径、文件路径等,不用作为查询条件的不用索引。

是否存储 (stored)

  • 是:将Field值存储在文档域中,存储在文档域中的Field才可以从Document中获取。

比如:商品名称、订单号,凡是将来要从Document中获取的Field都要存储。

  • 否:不存储Field值

比如:商品描述,内容较大不用存储。如果要向用户展示商品描述可以从系统的关系数据库中获取

Field类型

下边列出了开发中常用 的Filed类型,注意Field的属性,根据需求选择:

Field类 数据类型 Analyzed是否分词 Indexed是否索引 Stored是否存储 说明
StringField(FieldName,FieldValue,Store.YES)) 字符串 N Y Y或N 这个Field用来构建一个字符串Field,但是不会进行分词,会将整个串存储在索引中,比如(订单号,身份证号等)是否存储在文档中用Store.YES或Store.NO决定
FloatPoint(FieldName, FieldValue) Float型 Y Y N 这个Field用来构建一个Float数字型Field,进行分词和索引,不存储, 比如(价格) 存储在文档中
DoublePoint(FieldName,FieldValue) Double型 Y Y N 这个Field用来构建一个Double数字型Field,进行分词和索引,不存储
LongPoint(FieldName, FieldValue) Long型 Y Y N 这个Field用来构建一个Long数字型Field,进行分词和索引,不存储
IntPoint(FieldName, FieldValue) Integer型 Y Y N 这个Field用来构建一个Integer数字型Field,进行分词和索引,不存储
StoredField(FieldName, FieldValue) 重载方法,支持多种类型 N N Y 这个Field用来构建不同类型Field不分析,不索引,但要Field存储在文档中
TextField(FieldName, FieldValue, Store.NO) 或 TextField(FieldName,reader) 字符串或流 Y Y Y或N 如果是一个Reader, lucene猜测内容比较多,会采用Unstored的策略.
NumericDocValuesField(FieldName,FieldValue) 数值 - - - 配合其他域排序使用

对于数值类型的数据,分词可以实现范围查询。

索引维护

更新

管理人员通过电商系统更改图书信息,这时更新的是关系数据库,如果使用lucene搜索图书信息,需要在数据库表book信息变化时及时更新lucene索引库。

示例:

@Test
public void updateIndexTest() throws Exception{
    // 创建更改目标对象
    Document document = new Document();
    document.add(new StringField("id","100000003145", Field.Store.YES));
    document.add(new TextField("name", "xxx",Field.Store.YES));
    document.add(new IntPoint("price", 123));
    document.add(new StoredField("price", 123));
    document.add(new StoredField("image", "xxx.jpg"));
    document.add(new StringField("categoryName", "手机",Field.Store.YES));
    document.add(new StringField("brandName", "华为",Field.Store.YES));
    // 创建分词器
    Analyzer analyzer = new StandardAnalyzer();
    // 创建Directory目录对象,表示索引库的位置
    Directory dir = FSDirectory.open(Paths.get("D:\\dir"));
    // 创建IndexWriterConfig对象,指定切分词使用的分词器
    IndexWriterConfig config = new IndexWriterConfig(analyzer);
    // 创建IndexWriter输出流对象,指定输出的位置和使用的config初始化对象
    IndexWriter indexWriter = new IndexWriter(dir,config);
    // 修改,第一个参数:修改条件,第二个参数:修改成的内容
    indexWriter.updateDocument(new Term("id","100000003145"),document);
    // 释放资源
    indexWriter.close();
}

Lucene的修改实际是将对应的文档删除然后新建文档。

注意,不能添加一个域类型和其他文档的域不一样的文档,否则打开索引库会报错:

java.lang.IllegalArgumentException: cannot change field "brandName" from index options=DOCS to inconsistent index options=DOCS_AND_FREQS_AND_POSITIONS
    at org.apache.lucene.index.FieldInfo.update(FieldInfo.java:154) ~[luke-swing-with-deps.jar:?]
    at org.apache.lucene.index.FieldInfosBuilder.addOrUpdateInternal(FieldInfos.java:534) ~[luke-swing-with-deps.jar:?]
    at org.apache.lucene.index.FieldInfosBuilder.add(FieldInfos.java:559) ~[luke-swing-with-deps.jar:?]
    at org.apache.lucene.index.FieldInfosBuilder.add(FieldInfos.java:554) ~[luke-swing-with-deps.jar:?]
    at org.apache.lucene.index.FieldInfosBuilder.add(FieldInfos.java:480) ~[luke-swing-with-deps.jar:?]
    at org.apache.lucene.index.FieldInfos.getMergedFieldInfos(FieldInfos.java:154) ~[luke-swing-with-deps.jar:?]
    at org.apache.lucene.luke.models.util.IndexUtils.getFieldInfos(IndexUtils.java:379) ~[luke-swing-with-deps.jar:?]
    ......

删除

 @Test
public void deleteIndexTest() throws Exception{
    // 创建分词器,StandardAnalyzer对英文分词效果好,对中文是单字分词
    Analyzer analyzer = new StandardAnalyzer();
    // 创建Directory目录对象,表示索引库的位置
    Directory dir = FSDirectory.open(Paths.get("D:\\dir"));
    // 创建IndexWriterConfig对象,指定切分词使用的分词器
    IndexWriterConfig config = new IndexWriterConfig(analyzer);
    // 创建IndexWriter输出流对象,指定输出的位置和使用的config初始化对象
    IndexWriter indexWriter = new IndexWriter(dir,config);
    // 删除
    indexWriter.deleteDocuments(new Term("id","100000003145"));
    // 释放资源
    indexWriter.close();
}

原创文章,作者:彭晨涛,如若转载,请注明出处:https://www.codetool.top/article/lucene%e4%b8%ad%e7%9a%84%e5%9f%9f%e7%b1%bb%e5%9e%8b%e5%8f%8a%e6%96%87%e6%a1%a3%e7%9a%84%e6%9b%b4%e6%96%b0-%e5%88%a0%e9%99%a4/

发表评论

电子邮件地址不会被公开。