Lucene系列五:Field域

为何要写这一篇呢?主要是为了补充上一篇《系统架构及核心模块》中的章节,Field是文档中的域,包括Field名和Field值两部分,一个文档可以包括多个Field,Document只是Field的一个承载体,Field值即为要索引的内容,也是要搜索的内容。

1.最基本常用属性

是否分词(tokenized)

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

:不作分词处理

是否索引(indexed)

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

:不索引。该域的内容无法搜索到

是否存储(stored)

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

:不存储的Field无法通过Document获取

2. Field常用类型

数据类型

Analyzed

Indexed

Stored

说明

LongField(FieldName, FieldValue,Store.YES)

LongPoint(String name, int... point)

Long

Y

Y

YN

在Lucene 6.0中,LongField替换为LongPoint,IntField替换为IntPoint,FloatField替换为FloatPoint,DoubleField替换为DoublePoint。对int型字段索引,索引不存储,提供了一些静态工厂方法用于创建一般的查询,提供了不同于文本的数值类型存储方式,使用KD-trees索引

StringField(FieldName, FieldValue,Store.YES))

字符串

N

Y

YN

只索引但不分词,会将整个串存储在索引中,比如(订单号,身份证号等)

是否存储在文档中用Store.YES或Store.NO决定

StoredField(FieldName, FieldValue) 

重载方法,支持多种类型

N

N

Y

存储Field的值,不分析,不索引,可以用IndexSearcher.doc和IndexReader.document来获取存储的Field和存储的值

TextField(FieldName,FieldValue, Store.NO)

TextField(FieldName, reader)

 

字符串

或流

Y

Y

YN

索引并分词,不包括term vectors(词向量,下面会讲),例如通常用于一个body Field
NumericDocValuesField数值   适用于long型字段,用于评分排序和值检索,如果需要存储值,还需要添加一个单独的同名StoredField实例
BinaryDocValuesField    只存储不共享,例如标题类字段,如果需要共享并排序,推荐使用SortedDocValuesField
SortedDocValuesField    适用于String类型的Field排序,需要再添加同名的SortedDocValuesField

注意:重点重申ID(documentId),之前讲过文档编号,它默认是Document<stored,indexed,tokenized<id:5> 。

3. 按图书为例演示

图书id是否分词:不用分词,因为不会根据商品id来搜索商品
是否索引:不索引,因为不需要根据图书ID进行搜索
是否存储:要存储,因为查询结果页面需要使用id这个值。
图书名称是否分词:要分词,因为要将图书的名称内容分词索引,根据关键搜索图书名称抽取的词。
是否索引:要索引。
是否存储:要存储。
图书价格

是否分词:要分词,lucene对数字型的值只要有搜索需求的都要分词和索引,因为lucene对数字型的内容要特殊分词处理,本例子可能要根据价格范围搜索,需要分词和索引。
是否索引:要索引
是否存储:要存储

图书图片地址是否分词:不分词
是否索引:不索引
是否存储:要存储
图书描述

是否分词:要分词
是否索引:要索引
是否存储:因为图书描述内容量大,不在查询结果页面直接显示,不存储。 不存储是来不在lucene的索引文件中记录,节省lucene的索引文件空间, 如果要在详情页面显示描述,思路: 从lucene中取出图书的id,根据图书的id查询关系数据库中book表 得到描述信息。

4. IndexableField接口

各种Field都是IndexableField接口的实现,

public interface IndexableField {
  //获取名称
  public String name();
  //获取Field的类型
  public IndexableFieldType fieldType();
  //获取Field的权重
  public float boost();
  /** Non-null if this field has a binary value */
  public BytesRef binaryValue();
  /** Non-null if this field has a string value */
  public String stringValue();
  /** Non-null if this field has a Reader value */
  public Reader readerValue();
  /** Non-null if this field has a numeric value */
  public Number numericValue();
}

@Test
public void go_insertSortFeild() throws IOException {
    Document document = new Document();
    // 替换addStringField,addStringField,addTextField
    addIntPoint(document, "intValue", 10);
    writer.addDocument(document);
    document = new Document();
    addIntPoint(document, "intValue", 20);
    writer.addDocument(document);
    document = new Document();
    addIntPoint(document, "intValue", 30);
    writer.addDocument(document);
    writer.commit();
}
@Test
public void go_sortSearch() throws IOException {
    //第三个参数为true,表示从大到小
    SortField intValues = new SortField("intValue", SortField.Type.INT, true);
    TopFieldDocs search = searcher.search(new MatchAllDocsQuery(), 10, new Sort(intValues));
    ScoreDoc[] scoreDocs = search.scoreDocs;
    for (ScoreDoc scoreDoc : scoreDocs) {
        System.out.println(searcher.doc(scoreDoc.doc));
    }
}
@Test
public void go_byIntValue() throws IOException {
    String colName="intValue";
    //精确查询
    Query query = IntPoint.newExactQuery(colName, 5);
    ScoreDoc[] scoreDocs = searcher.search(query, 10).scoreDocs;
    for (ScoreDoc scoreDoc : scoreDocs) {
        System.out.println("精确查询:" + searcher.doc(scoreDoc.doc));
    }
}
private void addIntPoint(Document document, String name, int value) {
    Field field = new IntPoint(name, value);
    System.out.println(name + ",stored:" + field.fieldType().stored() + ",indexOptions:" + field.fieldType().indexOptions());//输出:stored:false,indexOptions:NONE
    document.add(field);
    //要排序,必须添加一个同名的NumericDocValuesField
    field = new NumericDocValuesField(name, value);
    document.add(field);
    //要存储值,必须添加一个同名的StoredField
    field = new StoredField(name, value);
    document.add(field);
}
private void addBinaryDocValuesField(Document document, String name, String value) {
    Field field = new BinaryDocValuesField(name, new BytesRef(value));
    document.add(field);
    //如果需要存储,加此句
    field = new StoredField(name, value);
    document.add(field);
}
private void addStringField(Document document, String name, String value) {
    Field field = new StringField(name, value, Field.Store.YES);
    document.add(field);
    field = new SortedDocValuesField(name, new BytesRef(value));
    document.add(field);
}
private void addTextField(Document document, String name, String value) {
    Field field = new TextField(name, value, Field.Store.YES);
    document.add(field);
    field = new SortedDocValuesField(name, new BytesRef(value));
    document.add(field);
}

细心的同学发现了:addIntPoint中的System.out.println明明输出的是indexOptions:NONE??
按理说,它不能被搜索的啊(go_byIntValue可以查询出结果),其实这点我也没想通,感觉实际上它却是被索引了。

IntPoint作为IndexableField实现类,它能直接setStored??

Field field = new IntPoint(name, value);
field.fieldType().setStored(true);
field.fieldType().setTokenized(true);

首先一般通过fieldType()方法获取到该Field对应的FieldType类型,,但是却并不能去调用FieldType一系列的set方法,否则会报:java.lang.IllegalStateException: this FieldType is already frozen and cannot be changed,这是因为各Field的子类中,都调用了type.freeze()方法,而该方法就可以阻止对fieldType做更改。

但7.4版本已经移除了set方法。

IntPoint类型的值应该如何被搜索呢?

细心的同学会发现,它可以通IntPoint.newExactQuery/newRangeQuery/newSetQuery ,在搜索一章中提具体讲用法

5. IndexableFieldType

这里就主要介绍这几个方法,更多

booleanstoreTermVectorOffsets()

True if this field's token character offsets should also be stored into term vectors.

True 表示字段的令牌字符偏移也应该存储到词向量中。

booleanstoreTermVectorPayloads()

True if this field's token payloads should also be stored into the term vectors.

True 表示这个字段的令牌有效负载也应该存储在词向量中。

booleanstoreTermVectorPositions()

True if this field's token positions should also be stored into the term vectors.

True 表示这个字段的的令牌位置也应该存储在词向量中。

booleanstoreTermVectors()

True if this field's indexed form should be also stored into term vectors.

True 表示这个字段的索引形式也应该存储到术语向量中。

词向量,对于每个文档中的每个字段,可以存储term vector,term vector由term文本和term频(包含该term的所有文档的数量以及该term在该文档中的频率,除非省略频率(IndexOptions.DOCS))组成。可以理解为是一种数学模型,这就为这个字段构建了一个微型的反向索引,可以从IndexReader.getTermVector(int,String)以面向文档的方式访问该字段。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值