Payload (元数据) 诞生于 Lucene 的2.2 版本,它是在 Lucene 2.1 索引文件格式的基础上扩展而来,提供了一种可以灵活配置的高级索引技术,在某些特定应用场景下能优化基于 Lucene 构建的应用的搜索性能。本文重点研究了 Payload 的实现原理、索引结构的变化、接口 API ,在本文的最后举例说明了 Payload 是如何帮助改善搜索体验的。

Lucene 是最初是由 Douglass R. Cutting 博士发布在自己主页上的一个 Java 全文信息检索工具包,后来成为 Apache Jakarta 家族中的一个开源项目,目前已经成为 Apache 基金会的顶级项目。索引是现代搜索引擎的核心,建立索引的过程就是把源数据处理成方便查询的索引文件的过程。 Lucene 采用的是一种被称为倒排索引 (Inverted Index) 的机制,倒排索引也是大多现代搜索引擎的基础。

Payload (元数据) 诞生于 Lucene 的2.2 版本,它是在 Lucene 2.1 索引文件格式的基础上扩展而来,提供了一种可以灵活配置的高级索引技术。本文重点研究了 Payload 的实现原理、索引结构的变化、接口 API ,在本文的最后举例说明了 Payload 是如何帮助改善搜索体验的。

Payload 的出现

倒排索引就是说我们维护了一个词条表,对于这个表中的每个词条,都有一个链表描述了有哪些文档包含了这个词条。假定我们有三篇文档 D0,D1,D2:

D0 = "it is what it is"
D1 = "what is it"
D2 = "it is a banana"

那么,我们可以创建如下倒排索引结构:

Term      Posting-list
"a": {2}
"banana": {2}
"is": {0, 1, 2}
"it": {0, 1, 2}
"what": {0, 1}

一般情况下,将一个词条所索引的文档(一般用文档编号表示)称之为 Posting,那么一个词条索引的多个文档就称之为 Posting-list。除了在 Posting-list 中记录文档编号,Lucene 也在Posting-list 中添加了词频和位置信息。词频的添加有助于结果的排序,位置信息的添加解决了短语检索的问题。

在Lucene 2.1 中,记录位置信息的即 .prx 文件,它的格式如下:

ProxFile (.prx) --> <TermPositions> TermCount
TermPositions --> <Positions> DocFreq
Positions --> <PositionDelta> Freq
PositionDelta --> VInt

仔细观察我们可以发现,文档 D0 中 what 词条是加粗显示而文档 D1 中的 what 则没有。显然,Lucene 2.1 的索引结构是无法表示出两者的差异。为了解决这个问题,从 Lucene2.2 开始,引入了 Payload 的概念。 Payload 即词条 (Term) 的元数据或称载荷, Lucene 支持用户在索引的过程中将词条的元数据添加的索引库中,同时也提供了在检索结果时读取 Payload 信息的功能。Payload 的诞生为用户提供了一种可灵活配置的高级索引技术,为支持更加丰富的搜索体验创造了条件。

那么 Lucene 是如何改进索引文件以支持 Payload 功能的呢?

回页首

索引结构的变化

为了更加形象的描述改进后的索引结构,我们用不同的颜色表示出文档 ID ,词频,位置和 Payload,如图 1 所示,(U表示下划线,B表示粗体)

图 1:Lucene的索引结构

对比 Lucene2.1 的索引结构,Lucene2.2 的索引结构的表达式如下:

ProxFile (.prx) --> <TermPositions> TermCount
TermPositions --> <Positions> DocFreq
Positions --> <PositionDelta,Payload?> Freq
Payload --> <PayloadLength?,PayloadData>
PositionDelta --> VInt
PayloadLength --> VInt
PayloadData --> bytePayloadLength

从上面的索引表达式中可以看出只有当一个词汇包含 Payload 信息时,Lucene 才会为之分配相应的 Payload 存储空间,这是一种高效率的空间实现。Lucene2.2 之后的 Payload 特指词条的元数据,那么文档的元数据如何表示呢?

我们知道,Lucene 中 Document 由 Field 组成,而 Field 由 Term 组成,文档的 Payload 可以用存储的 Field 表示。这样存在的问题是,如果需要读取大量的文档的元数据,因为 Field 的索引信息与存储信息是分开的,那么 I/O 效率将是较差的。而 Payload 信息则是直接存储在索引中,因此可以利用词条的 Payload 功能存储文档级别的元数据。文档级 Payload 可表示为如下图2所示格式(省略了词频和位置信息):

图 2:文档级的 Payload 表示

如图2所示,以文档的 url 信息为例,通过为每一个文档构造一个特殊的词条 ”url” ,将每个文档的 url值作为
payload 信息,把 Payload 与文档编号关联起来,这样就可以实现文档级的 Payload。

回页首

Payload 相关的 API

从 Lucene2.2 的索引结构可以看出,Payload 的存储与词条的位置信息是紧密联系在一起的,因此 Payload 的存储和检索 API 位于Token类和 TermPositions 类当中。

向词条中存储 Payload 信息

org.apache.lucene.analysis.Token
void setPayload(Payload payload)

Payload 信息的构造函数

org.apache.lucene.index.Payload
Payload(byte[] data) Payload(byte[] data,
int offset,
int length)

从位置信息中检索 Payload

org.apache.lucene.index.TermPositions
boolean next();
int doc()
int freq(); int nextPosition(); int getPayloadLength();
byte[] getPayload(byte[] data,
int offset)

回页首

Payload 的应用场景举例

场景一:改进的 Lucene 的区间检索

日期检索是区间检索的常见例子,如用户需要在图书馆中检索特定年代的图书,满足如下条件:

Date>1954/08/01 & Date<1955/08/01

常见的做法就是将日期作为一个独立 Field 进行存储,利用 RangeQuery 进行区间检索,Posting-list 的格式如图3中左图所示。如果图书日期分布区间很广,用 Field 存储日期信息,我们需要将日期细化到年月日进行存储,因此词条数目是非常庞大的。这种情况下,我们可以利用 Payload 功能来减少词条的数目,提高检索效率,可以将日期的年月作为词条,日作为 Payload 信息,这几乎将词条数目减小了近 30 倍,改进后的存储结构如图3右图所示:

图 3:使用 Payload 存储日期信息

场景二:提高特定词汇的评分

利用 Payload 功能,还可以提高文档中特定词汇的评分,如黑体词汇、斜体词汇等,从而优化搜索结果排序。

下面还以文档 D0 和 D1 为例说明如何设置和检索 Payload。

D0 = "it is what it is"
D1 = "what is it"

Step1:在Analyzer处理过程中,为特殊词汇添加评分Payload

final byte BoldBoost = 5;

final byte ItalicBoost = 5;

Token token = new Token(…);

if (isBold) {//如果是黑体字
token.setPayload(
new Payload(new byte[] {BoldBoost}));
}else if(isItalic){//如果是斜体字
token.setPayload(
new Payload(new byte[] { ItalicBoost }));
}

return token;

Step2:重写Similarity (主要负责排名和评分)

Similarity boostingSimilarity =
new DefaultSimilarity() {
// @override
public float scorePayload(byte [] payload,
int offset,
int length) { //读取payload的值,payload存储的即为词汇的评分。
if (length == 1) return payload[offset];
};

Step3:使用重写的boostingSimilarity进行检索

Query btq = new BoostingTermQuery(
new Term(“field”, “what”)); Searcher searcher = new IndexSearcher(…);
Searcher.setSimilarity(boostingSimilarity);

Hits hits = searcher.search(btq);

回页首

总结

Payload 是 Lucene 一个允许在索引中为词条储存元数据信息。希望通过阅读本文,你可以对Payload 功能有一个整体的了解,进而可以灵活运用 Payload 的功能来优化具体的应用。

Lucene Payload 的研究与应用的更多相关文章

  1. Lucene.net项目研究说明

    最近项目需要全文检索,所以找了几个开源的.NET检索项目,如:Lucene.net,Sphinx,Hubble.net.最后选择使用Lucene.ne来实现全文检索.至于原因嘛,可以参考下面几点: 1 ...

  2. Lucene底层原理和优化经验分享(1)-Lucene简介和索引原理

    Lucene底层原理和优化经验分享(1)-Lucene简介和索引原理 2017年01月04日 08:52:12 阅读数:18366 基于Lucene检索引擎我们开发了自己的全文检索系统,承担起后台PB ...

  3. 一步一步学习FastJson1.2.47远程命令执行漏洞

    本文首发于先知:https://xz.aliyun.com/t/6914 漏洞分析 FastJson1.2.24 RCE 在分析1.2.47的RCE之前先对FastJson1.2.24版本中的RCE进 ...

  4. Lucene 评分机制二 Payload

    这里使用的Lucene4.7.0和Lucene3.X稍有不同 有下面三段内容,我想对船一系列的搜索进行加分 bike car jeep truck bus boat train car ship bo ...

  5. Lucene的评分(score)机制研究

    首先,需要学习Lucene的评分计算公式—— 分值计算方式为查询语句q中每个项t与文档d的匹配分值之和,当然还有权重的因素.其中每一项的意思如下表所示: 表3.5 评分公式中的因子 评分因子 描 述 ...

  6. Lucene&Solr框架之第一篇

    2.信息检索 信息检索是计算机世界中非常重要的一种功能.信息检索不仅仅是指从数据库检索数据,还包括从文件.网页.邮件.用户手输入的内容中检索数据.通过怎样的高效方式将用户想要的信息快速提取出来,是计算 ...

  7. 原创:史上对BM25模型最全面最深刻的解读以及lucene排序深入讲解

    垂直搜索结果的优化包括对搜索结果的控制和排序优化两方面,其中排序又是重中之重.本文将全面深入探讨垂直搜索的排序模型的演化过程,最后推导出BM25模型的排序.然后将演示如何修改lucene的排序源代码, ...

  8. Lucene的分析资料【转】

    Lucene 源码剖析 1 目录 2 Lucene是什么 2.1.1 强大特性 2.1.2 API组成- 2.1.3 Hello World! 2.1.4 Lucene roadmap 3 索引文件结 ...

  9. Lucene提供的条件判断查询

    第一.按词条搜索 - TermQuery query = new TermQuery(new Term("name","word1"));hits = sear ...

随机推荐

  1. Android onTouchEvent和setOnTouchListener中onTouch的区别

    OnTouchEvent()方法 是获取的对屏幕的各种操作,比如向左向右滑动,点击返回按钮等等. 属于一个宏观的屏幕触摸监控. OnTouchListener()方法 是获取某一个控件某一个View的 ...

  2. js实现把中文、英文标点转换

    所有英文符号转换成中文的符号 <SCRIPT LANGUAGE="JavaScript"> <!-- function meizz(str) { var tmp ...

  3. Django之搭建学员管理系统

    GET请求传参数的方式: /xxx/?k1=v1&k2=v2 ? 前面的是URL ?后面的是请求的参数 多个参数之间用&分隔 POST请求传数据: 是放在请求体里面的 表结构设计. - ...

  4. go set up on ubuntu

    sudo apt-get install golang-go package main import ( "fmt" "runtime" ) func main ...

  5. 解决跨域POST登录中IE不能正常工作的bug

    结合我的这篇blog <简单实用的跨域表单POST提交> 文章,这篇blog中的思路是解决在www.a.com站中登录 同时要把关联站www.b.com登录状态也设置成登录状态,在a中获取 ...

  6. HihoCoder 1122二分图二 ---最大匹配之匈牙利算法

    二分图二•二分图最大匹配之匈牙利算法 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 上一回我们已经将所有有问题的相亲情况表剔除了,那么接下来要做的就是安排相亲了.因为过 ...

  7. 关于fpga的m9k的部分理解

    1.控制信号包括时钟使能,读写使能,字节使能,地址使能,异步清零等 2.可配置为单端口,简单双端口,真双端口,fifo,rom,移位寄存器. 3.关于移位寄存器模式的介绍如下: 一个 ( w × m ...

  8. eclipse “”base revision” vs. “latest from repository”

    base revision(基本版本):代表的是最近一次从svn服务器上面获取的版本内容:本质还是本地版本,只不过这个版本是上次从服务器上面获取的. lastest from resource(资源库 ...

  9. POJ2226(最小顶点覆盖)

    Muddy Fields Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 10044   Accepted: 3743 Des ...

  10. Linux:常用命令讲解(系统、防火墙、提权与文件传输)

    一.系统用户操作指令 一般在 Linux 系统中有多个账号,但一般不推荐使用 root 账号,因为 root 账号的权限太大,如果账号泄露会有安全隐患: 一般配置软件时也不要在 root 账号下进行: ...