zoukankan      html  css  js  c++  java
  • 搜索引擎lucene实现二半吊子的论调之Document和Field

    本来打算先写写analysis包,因为那个组件包是基础。但写着写着就觉得没有入口的说明,就跳到那一部分实在对不起自己和各位的理解。于是咱就先看看Document和Field,这两个用于索引和查询的数据结构。

    我们大多数人用过数据库,知道一个表里面的一行。如粗糙的下图所示:

    新建位图图像

    这个是关系型数据库的典型存储方式。我们在进行数据查询的时候,也是提供字段值或者是模式等条件。那么lucene作为一个全文检索的解决方案,从表面来看,也是类似于关系型数据库方式。它为我们提供了

    统一的数据索引接口(IndexWriter)和查询接口(IndexSearcher)。在我们这次要说明的Document和Field,我们也可以对应理解成关系型数据库的一个数据行和字段。于是再对应一下,可以将IndexWriter理解

    成SQL里面的insert语句,而IndexSearcher对应成select语句。表面上就是这样的,最多是使用方式不同。

    有了这么一层考虑之后,再来理解Document和field,我想(嗯,是我想象的)应该比较容易了。

    在《体系结构》的例子中,有如下代码:

    doc.add(new Field("fieldname", text, TextField.TYPE_STORED));

    这表示啥意思,从上面的对比说明来看,就是在构造一行,往行里面添加列值(Field)。

    Ok,我们有了点感觉之后再来看看org.apache.lucene.document包。

    这里都是从lucene4.0里面拉出来的,跟3.x里面的一些用法有比较大的区别。(各位用3.x的同学,要注意api上的变化)

    如果我们就是要建立针对学生成绩表里面姓名和成绩的全文检索(这里应该考虑一下,到底什么是全文检索?这里的全文是什么意思?所谓的“全”,到底是哪个范围里面的“全”?这些都有助于各位同学建立有针对性的搜索系统,而不仅仅是把数据库里面的查询搬到lucene里面),那应该如何构造用于建立索引的Document数据?

    构建一个Document:(So Easy!)

    Document doc = new Document();

    接下来,往Document中存放各个字段:

    doc.add(new Field("name", text, TextField.TYPE_STORED));//这种方式还是从3.x一直用过来的

    3.x里面的那个持久的Field构造函数:

    Field(String name, String value, Field.Store store, Field.Index index, Field.TermVector termVector)

    已经被弃用了。我第一次使用这个东西也被迷惑一小下。怎么要有这么多变量来说明这个字段的属性。尤其是,加入一个属性,我肯定是想要建立索引的(大部分情况下,针对文本内容来说)。

    现在4.0里面推荐如下方式:

    doc.add(new TextField("name", text, Store.YES));

    由原来的Field分割成如下些个子类:

     DoubleFieldFloatFieldIntFieldLongFieldStoredFieldStringField, TextField ……

    请特别注意上面的省略号,里面还有很多,跟特定类型对应Field子类。鉴于篇幅和勤快程度的考虑,我就不多列了。

    有了以上几个类,我们在add field时,应该更加明确了,就不会像以前只是笼统的区分Text和Number。

    而且在新api里面,Field.Index枚举类型被弃用了,其替代品是FieldType,这个类里有关于本字段数据处理的各种元数据,字段如下:

      private boolean indexed;
      private boolean stored;
      private boolean tokenized = true;
      private boolean storeTermVectors;
      private boolean storeTermVectorOffsets;
      private boolean storeTermVectorPositions;
      private boolean storeTermVectorPayloads;
      private boolean omitNorms;

    …………

    从这个重构方式里,我们也能看到lucene越来越成熟了,元数据划分归类也更加细腻,而不是像以前那样,让新用户来决定各种显而易见的属性。(请把这句话当成废话,但是请考虑一下其重构原则)

    言归正传,加完姓名的field之后,我们接着添加成绩字段:

    doc.add(new FloatField(“score”, 59.9F, Field.Store.YES);

    通过这个构造函数(FloatField(String name, float value, Field.Store stored)),我们可以创建一个名叫score,值为59.9,且要保存到索引文件的FloatField。这里面也要特别说明一下。
    请看这个构造函数的源码:

    public FloatField(String name, float value, Store stored) {
        super(name, stored == Store.YES ? TYPE_STORED : TYPE_NOT_STORED);
        fieldsData = Float.valueOf(value);
      }

    FloatField将Field.Store转换成了TYPE_STORED : TYPE_NOT_STORED(显而易见),这两个对象都是FieldType实例。再来看看源码(以TYPE_STORED为例):

    static {
        TYPE_STORED.setIndexed(true);
        TYPE_STORED.setTokenized(true);
        TYPE_STORED.setOmitNorms(true);
        TYPE_STORED.setIndexOptions(IndexOptions.DOCS_ONLY);
        TYPE_STORED.setNumericType(FieldType.NumericType.FLOAT);
        TYPE_STORED.setStored(true);
        TYPE_STORED.freeze();
      }

    这里要特别注意下,TYPE_STORED.setNumericType(FieldType.NumericType.FLOAT);这句说明我们可以在搜索时,针对score这个字段排序。

    于是,我们也就要考虑一下,我们的字段类型的关联问题,各位同样可以跟数据库表关联起来理解。

    文本类型(TextField):是一大块需要经过分词的文本;

    字符串类型(StringField):是一个不需要分词,而直接用于索引的字符串;

    数字类型(LongField, FloatField, DoubleFieldIntField):首先是一个不变的属性值,这类字段还有一个主要用途,就是可以用于对搜索的返回结果集排序或是按范围查询。

    DocValues类型(类名中含有DocValues字样的Field子类):这些个类可以理解成一个专门服务于Document,且可以用于排序,范围查询等方面的字段。

    有了上面的说明,各位在使用时,尤其是在搜索时,对于字段是否可以排序,是否可按范围查询等问题,也就有答案了。

    到这里,对document包的说明也应该是差不多了。但是数据库里面还有date类型的字段,可惜lucene里面没有对date的直接支持。但是各位都知道date可以变成long型的字段。这样各位就可以针对时间进行存储,排序,或是按范围查询了。

    ok,这次就到这里,要接下去完成还是二二半吊子的analysis部分了。

  • 相关阅读:
    闭关
    我现在很好
    asp.net看不明白怎么办?
    中秋节
    今天很开心
    偶尔伤感
    现在是10月4日了!
    2006的最后一天
    十多天都不写博客了
    呵呵  最近很忙  但是很充实!
  • 原文地址:https://www.cnblogs.com/ericchen/p/2787648.html
Copyright © 2011-2022 走看看