倒排索引压缩(无损压缩)

Index Compression(压缩比vs解压效率)

主要是对倒排索引(inverted index)中的倒排列表(postings list)进行编码压缩

      编码方法:

1.D-gaps:对有序编号(如docid)进行差值(d-gaps)编码。(处理小数据需要小代码量,处理时间短)编码并没有定义存储数据的比特模式,所以他自身不节省任何空间。

2.Elias-γ Code结合了一元编码和二进制编码。编码数字k需要计算两个值:

     

       倒排索引压缩(无损压缩)_第1张图片

3. Elias-δCode通过改变kd的编码方式,将kd分解为

倒排索引压缩(无损压缩)_第2张图片

Kdd使用一元编码,kdr用二进制编码, kr仍然用二进制编码

4. Variable Byte Code:每个字节的低7位是二进制数,高位是一个决定位。编码的最后一个字节高位位置为1,位置为0。处理器一般是以字节为处理单位,所以Variable ByteCode速度快,但是处理大数据压缩比不高


5. Golomb编码中,整数x用两部分来表示,商和余数。商的计算公式为 ,余数的计算公式为r =( q*k )-1,在这里 k是 Golomb编码算法的基础,

如果 r< p,整 数可以用 ⌊log2k⌋位来存储 , 否则它将需要 ,在这里P是分界点,计算方法为p=2⌊log2k⌋+1-k。

当 r< p时,Golomb编 码用q个0,1个1,还有r的二进制表示。否则表示方法为 q个0,1个 1,以及 r + p的二进制表示。这样,整数 9可用 k = 3编码为00,1,11。

参数k的选择是至关重要的。如果选择得不好,编码后的整数会变得非常大 ,需要很长时间来解压 。Witten et al.(1994)认为假定倒排表 中的整数符合 Bernoulli模型, 则一列整数a的k值用 k≈0.69x平均值(a)来计算。

Williams 和Zobel描述了对Golomb编码实施优化的方法,并且认为常规的对整数的Golomb编码比Elias gamma编码和Elias delta编码解码更快并且更加节省空间。

倒排索引压缩(无损压缩)_第3张图片


6. BinaryInterpolative Coding二进制插入编码用相邻数的信息来编码一个单调递增的整数数列。

        如果在整数数列X1中,对于任一给定的整数xi ,前一个数xi-1和后一个数xi-2是已知的,xi的大小是在(xi-1+1, xi-2-1) 的范围内,所需的最大位数为 log2(xi-1-xi-2-2) 。解码时需要xi-1和xi-2的信息,所以数列 X2是从原先的X1得到的,也就是说每个从表 X1 得到的整数都在X2中, 这样也就可以递归地进行编码 。

       二进制插入编码(BIC)利用相邻两个数的信息,对单调递增的倒排列表进行紧凑的递归编码,不仅压缩率高,而且解码速度快;该算法还考虑了文档中词出现的频率分布,以聚类( clustering)的方式对倒排列表的压缩性能进行优化,有效地提高了索引的空间效率.

            7.other compression:

InvertedIndex Compression Using Word-Aligned Binary Codes    -Anh V, Moffat A.2005 (基于字行的二进制编码方式)

Performanceof Compressed Inverted List Caching In Search Engines  -Zhang Jiang-Gong,LoneXiao Hui,Suel T.2008

Invertedindex compression and query processing with optimized document ordering   -Yan H, Ding S, Suel T.2009

基于字行的二进制编码方式(Word-AlignedBinary Code,WABC)对索引进行压缩;该编码具有字节操作的优点,其紧凑的二进制特性不仅保证了索引的压缩性能,而且提高了查询时倒排列表的解码速度.

Performance ofCompressed Inverted List Caching In Search Engines中同时考虑了搜索引擎中的索引压缩与索引缓存机制,并对变比特编码等几种压缩算法的性能进行了比较分析.为了进一步提高检索性能.

Inverted indexcompression and query processing with optimized document ordering 对倒排列表文档标识(Identity,ID)整数集的升序特征进行了研究,通过更加紧凑的表示方法、快速求交集算法以及对文档ID顺序进行优化,提高查询效率。

"Index Compression Using 64-Bit Words", Anh, Moffat(最近才发现的好东东,对以往的压缩方法的概括集成。待了解。开源地址:http://ww2.cs.mu.oz.au/~alistair/coders-64bit/) 

以及作者Alistair Moffat的相关研究:http://ww2.cs.mu.oz.au/~alistair/abstracts/


参考《Compression of inverted Indexes For FastQuery Evaluation》论文源码地址:http://www.seg.rmit.edu.au/projects.html)

 对于posting 三元组<Docid, Frequence, Position>:

1.    首先对Docid,Position经过d-gaps编码处理。

2.    然后对posting中的3个元素采用不同的编码方法组合。如Dvbyte-FGol-PGamma

如果选择Elias-γ Code,Elias-δCode,VariableByte Code, Golomb进行实验对比,则共有24种组合方案。


这里只介绍了倒排索引中的对整型数据的编码压缩方法,相关的其他压缩方法参考wikipedia:http://en.wikipedia.org/wiki/Data_compression

另外参考:1.google group varint 无损压缩解压算法的高效实现

    2.Doclist压缩方法简介


附lemur中RVLCompress的压缩方法代码:(可变字节编码压缩方法v-bytes coding)

/********************************************************
	@editor:weedge E-mail:[email protected]
	@date:2011/08/30
	@comment:
		1.对int32进行压缩,返回压缩后的长度 
		2.对压缩byte型数据进行解压,返回解缩后的长度
*******************************************************/

#include "RVLCompress.hpp"
#include <stdlib.h>
#include <stdio.h>

#define pow2_7  128
#define pow2_14 16384
#define pow2_21 2097152
#define pow2_28 268435456

#define pow2_31 2147483648U

#define RVL_COMPRESS_MASK                      ((1<<7)-1)//0111 1111
#define RVL_COMPRESS_TERMINATE_BIT             (1<<7)//左移7位,1000 0000
#define RVL_COMPRESS_BYTE( d, in, b )          d[b] = (char) ((in >> 7*b) & ((1<<7)-1))//取高7*N位
#define RVL_COMPRESS_TERMINATE( d, in, b )     d[b] = (char) ((in >> 7*b) | (1<<7))//取低7*N位,并置高位为1

///return number of bytes in result
static int compress_ints (int *data_ptr, unsigned char *out_ptr, int size);

/// returns number of ints decompressed
static int decompress_ints(unsigned char *data_ptr, int *out_ptr, int num_bytes);

/***************************************
对压缩byte型数据进行解压,返回解缩后的长度
	@editor:weedge
	@parameter:
		data_ptr:待解压的byte型数据
		out_ptr: 解压后的int32型数据
		num_bytes:待解压的数据大小
**********************************/
int decompress_ints (unsigned char *data_ptr,int *out_ptr,int num_bytes)
{

  unsigned char *data_end_ptr = data_ptr + num_bytes;//指向数组末尾
  unsigned char *data_curr_ptr;
  int *out_ptr_end = out_ptr;

  for (data_curr_ptr=data_ptr; data_curr_ptr<data_end_ptr; out_ptr_end++) //遍历数组中的每个char
  {
    if (*data_curr_ptr & 128) //和1000 0000进行与操作,判断最高位是否为1
	{
      *out_ptr_end = 127 & *data_curr_ptr;
      data_curr_ptr ++;
    } 
	else if (*(data_curr_ptr+1) & 128) 
	{
      *out_ptr_end = *data_curr_ptr |
        ((*(data_curr_ptr + 1) & 127) << 7);
      data_curr_ptr += 2;
    } 
	else if (*(data_curr_ptr+2) & 128) 
	{
      *out_ptr_end = *data_curr_ptr |
        (*(data_curr_ptr + 1) << 7) |
        ((*(data_curr_ptr + 2) & 127) << 14);
      data_curr_ptr += 3;
    } 
	else if (*(data_curr_ptr+3) & 128) 
	{
      *out_ptr_end = *data_curr_ptr |
        (*(data_curr_ptr + 1) << 7) |
        (*(data_curr_ptr + 2) << 14) |
        ((*(data_curr_ptr + 3) & 127) << 21);
      data_curr_ptr += 4;
    } 
	else 
	{
      *out_ptr_end = *data_curr_ptr |
        (*(data_curr_ptr + 1) << 7) |
        (*(data_curr_ptr + 2) << 14) |
        (*(data_curr_ptr + 3) << 21) |
        ((*(data_curr_ptr + 4) & 127) << 28);
      data_curr_ptr += 5;
    }
  } // for
  
  return (out_ptr_end - out_ptr);
}

/**********************************************************
注意:该int32数据在压缩前,进行d-gaps编码操作,节省压缩时间。
对int32进行压缩,返回压缩后的长度
 
	@parameter:
		data_ptr:待压缩的int数据
		out_ptr: 压缩后的byte数据
		size:待压缩的数据大小
**********************************/
int compress_ints (int *data_ptr,unsigned char *out_ptr,int size)
{
  int  *data_end_ptr = data_ptr + size;//指向数组末尾
  int  *data_curr_ptr;
  unsigned int n;
  unsigned char *out_ptr_end = out_ptr;

  for (data_curr_ptr=data_ptr; data_curr_ptr<data_end_ptr; data_curr_ptr++) //遍历数组中的每个int
  {
    n = (unsigned int)*data_curr_ptr;

    if (n < pow2_7)//小于128
      *out_ptr_end++ = 128 | n;//加128,即把n的二进制数值的首位置1
    else if (n < pow2_14) //128<= n < 16384(2(14))
	{
      *out_ptr_end = 127 & n;//和0111 1111进行与操作,取n的低7位
      *(out_ptr_end + 1) = 128 | (n >> 7);//右移7位,取n的高7位,并置高位(8位)为1
      out_ptr_end += 2;
    } 
	else if (n < pow2_21) 
	{
      *out_ptr_end = 127 & n;//和0111 1111进行与操作,取n的低7位
      *(out_ptr_end + 1) = 127 & (n >> 7);//右移7位,取n的高7位,并置高位(8位)为1
      *(out_ptr_end + 2) = 128 | (n >> 14);
      out_ptr_end += 3;
    } 
	else if (n < pow2_28) 
	{
      *out_ptr_end = 127 & n;
      *(out_ptr_end + 1) = 127 & (n >> 7);
      *(out_ptr_end + 2) = 127 & (n >> 14);
      *(out_ptr_end + 3) = 128 | (n >> 21);
      out_ptr_end += 4;
    } 
	else 
	{
      *out_ptr_end = 127 & n;
      *(out_ptr_end + 1) = 127 & (n >> 7);
      *(out_ptr_end + 2) = 127 & (n >> 14);
      *(out_ptr_end + 3) = 127 & (n >> 21);
      *(out_ptr_end + 4) = 128 | (n >> 28);
      out_ptr_end += 5;
#if 0
      if (n >= pow2_31) 
	  {
        cerr << "WARNING: value exceeded int limit in compression" << endl;
      }
#endif
    }
  } // for

  return (out_ptr_end - out_ptr);
}

int main()
{
/*test compress_ints*/	

/*test decompress_ints*/

	return 0;
}



你可能感兴趣的:(算法,search,processing,byte,caching,compression)