返回首页

{A}简介
华压缩的BitArray。NET实现互联网和搜索,没有找到一个后,我决定撰写和发表的文章在这里所以。NET社区不会被排除在外,所有可用的实现在Java语言中。这关系到一个位图索引数据库技术非常先进的话题,我需要为我即将到来的RaptorDB文件数据存储的数据库引擎。它是什么?
一个BitArray中是一个真/假或位在一个紧凑的形式的数据存储在Int32的对象数组。NET库的数据结构。哇音或字对齐混合BitArray中是一个特殊的运行长度压缩一个BitArray中节省了很多空间和内存的版本。在Java中存在的所有的实现基本上是重复的,压缩内部存储格式一个bitset的功能,即是AND,OR,NOT,和XOR操作。
我在执行中,我推迟本身的BitArray的功能,只需要添加压缩和解压例程。这是比牺牲的内存使用Java的方式更快。为了克服这个问题,我还添加了一个FreeMemory的方法来释放BitArray中的内容,并保持压缩的内容。可以说,如果您使用的是100万比特,然后全面实施执行比我更高性能,但对于大多数用例,我们大部分是在10亿位的范围。
这种原始的方法是在美国能源部的伯克利实验室发明的,它是一个名为FastBit项目和用于高能物理部实验,你可以在这里看到:。我为什么要关心?
,你还等什么?问。那么,提到之前,BitArrays所谓的位图索引({A6})和列列而不是行存储数据的数据库索引技术。你可能知道的一个例子是微软的Excel中的PowerPivot可以在几秒钟内处理数百万行。有趣的是,微软最近才宣布,在即将到来的SQL Server平台的位图索引的执行情况,2008年后的R2。长期以来,人们一直在使用的其他RDBM厂商,如Oracle。它如何工作
华压缩算法如下:取31位从阵列。如果所有的零,然后递增31计数为零。如果的计数GT;位32 = 1和第31位0,然后输出32位= 1和0-30的计数。如果所有的,然后递增的计数31。如果零计数GT;位32 = 1和第31位0,然后输出32位= 0和0-30 =零计数。否则输出为32位位32 = 0的31位。零或者如果罪名GT;如上0,然后输出。
从上面的,在最坏的情况下,你会得到更多N/31位编码或3%左右提高到原来的大小。您的
WAHBitArray本质上是相同的NET Framework中的标准的BitArray,添加以下。FreeMemory():这将首先压缩内部的BitArray,然后释放它使用的内存。GetCompressed():这将压缩目前的BitArray,然后返回一个UINT数组。CountOnes CountZeros(),():计算数组中的相应位。GetBitIndexes(BOOL):返回一个枚举,使用各自的位位置的产量,例如,如果该位的数组包含10001 ...这将返回整数0,4,...如果bool参数是真实的,1,2,3,... ...如果bool是假的。(),设置():方法与实施自动调整大小,并没有例外。DebugPrint():生成一串1和0值。使用代码
要创建一个WAHBitArray,你可以做到以下几点:

WAHBitArray ba1 = new WAHBitArray(1000000); // 1 million bits

// 2 million bits from another bitarray

WAHBitArray ba2 = new WAHBitArray(new BitArray(2000000));

WAHBitArray ba3 = new WAHBitArray(1000000, new uint[] { /* compressed values here */});

// from a compressed list of uint

执行操作,您可以执行以下操作:{C}使用代码V1.3
1.3版本,你并不需要指定大小的BitArray中的所有操作,会自动根据需要调整大小。
WAHBitArray ba1 = new WAHBitArray(); // no need to specify the size

WAHBitArray ba3 = new WAHBitArray(new uint[] { /* compressed values here */});

// from a compressed list of uint
兴趣点BitArray类是密封的微软,所以继承它是不可能的。BitArray中抛出一个异常,如果两个BitArrays长度等于没有位操作,WAHBitArray使它们作为操作前最大的相同。BitArray中,必须在32个增量调整大小,否则压延压缩位。2.0版
对于额外的速度,在压缩和解压的位,而事实上,不给BitArray中的内部数据结构的访问。NET Framework实现,我不得不在WAHBitArray重写所有的BitArray功能。
使用反射看到的BCL的BitArray之一的内部实现,可以看到下面的片段:
// AND operation

for (int i = 0; i < array.Length; i++)    

    array[i] &= val[i];



// OR operation

for (int i = 0; i < array.Length; i++)

    array[i] |= val[i];



// XOR operation

for (int i = 0; i < array.Length; i++)

    array[i] ^= val[i];

正如你可以看到,位操作完成的Int32值。

访问内部UINT现在,[]位,压缩方法,得到31位的数据块,而不是逐个。这是在Take31Bits()方法,发现在_uncompressed列表中相邻的两个uint值,并有如下几个位操作:
public WAHBitArray And(WAHBitArray op)

{

	this.CheckBitArray(); // check the bit array is uncompressed



	uint[] ints = op.GetUncompressed(); // get the values



	FixSizes(ints, _uncompressed); // make the sizes the same



	for (int i = 0; i < ints.Length; i++)

		ints[i] &= _uncompressed[i]; // do the AND operation



	return new WAHBitArray(false, ints); // return a new object

}

压缩及解压缩例程被改写操作UINT []数组如下:
private void Compress()

{

	_compressed = new List<uint>();

	uint zeros = 0;

	uint ones = 0;

	int count = _uncompressed.Count << 5;

	for (int i = 0; i < count; )

	{

		uint num = Take31Bits(i);

		i += 31;

		if (num == 0)

		{

			zeros += 31;

			FlushOnes(ref ones);

		}

		else if (num == 0x7fffffff)

		{

			ones += 31;

			FlushZeros(ref zeros);

		}

		else

		{

			FlushOnes(ref ones);

			FlushZeros(ref zeros);

			_compressed.Add(num);

		}

	}

	FlushOnes(ref ones);

	FlushZeros(ref zeros);

}



private void Uncompress()

{

	int index = 0;

	List<uint> list = new List<uint>();

	if (_compressed == null)

		return;



	foreach (uint ci in _compressed)

	{

		if ((ci & 0x80000000) == 0) // literal

		{

			this.Write31Bits(list, index, ci & 0x7fffffff);

			index += 31;

		}

		else

		{

			uint c = ci & 0x3ffffff;

			if ((ci & 0x40000000) > 0) // ones count

				this.WriteBits(list, index, c);



			index += (int)c;

		}

	}

	this.ResizeAsNeeded(list, index);

	_uncompressed = list;

}

因为服用或更新31位的数据可以重叠2个相邻的uint值,一些位按摩如下:
private uint Take31Bits(int index)

{

	long l1 = 0;

	long l2 = 0;

	long l = 0;

	long ret = 0;

	int off = (index % 32);

	int pointer = index >> 5;



	l1 = _uncompressed[pointer];

	pointer++;

	if (pointer < _uncompressed.Count)

		l2 = _uncompressed[pointer];



	l = (l1 << 32) + l2;

	ret = (l >> (32 - off)) & 0x07fffffff;



	return (uint)ret;

}
历史初始版本V1.0:2011年6月22日V1.1更新:2011年6月24日位操作现在返回,而不是BitArray中WAHBitArrayAnbsp;位操作将作为输入一个WAHBitArray或BitArray中CountZeros(),CountOnes()方法添加添加GetBitIndexes()方法V1.2更新:2011年6月28日获取,设置自动调整大小的方法V1.3更新:2011年7月23日删除需要指定初始大小在32个增量的问题修复调整大小BitArray的算术错误修复DebugPrint()方法来实现更新V2.0完全重写优化的压缩和解压〜9x的速度增加所有的位操作都没有BCL的BitArray内部

回答

评论会员:AndyHo 时间:2012/02/04
迈赫迪
好样的!我已经实现一个bitset类的BitArray,基于一个老有人在这里或那里做的工作(不记得了)
此BitSet已广泛用于我,所以我习惯了,我已经实施了几项性能的提高,让我来告诉你其中的一些:

你应该实现的GetHashCode(),equals()方法允许类指数词典或Hashtable
toString()方法被重写(调试时有用)

这里是我的
代码
public override int GetHashCode()

{

    int h = 0;

    if (_compressed != null)

    {

        foreach (uint u in _compressed) h ^= (int)u;

    }

    if (_uncompressed != null)

    {

        foreach (uint u in _uncompressed) h ^= (int)u;

    }

    return h;

}

这里是一个不那么轻巧的比较多一点的工作,您可能会比较INT INT通过,如果两个数组是压缩或解压缩,但急于这应该工作的罚款,(实际上)!

public override bool Equals(object obj)

{

    if (obj != null && obj is WAHBitArray)

    {

        WAHBitArray w = obj as WAHBitArray;

        w.CheckBitArray();

        CheckBitArray();

        return w._uncompressed.Equals(_uncompressed);

    }

    else return false;

}
其多次需要看到,如果BitArray中是空的(即后和()操作),这就产生了财产的需要,所谓"零",这是很好的实施像这样的,以极快的例行的:

public bool Zero

{

    get

    {

        CheckBitArray();

        foreach (uint ui in _uncompressed)

        {

            if (ui != 0)

                return false;

        }

        return true;

    }

}

即使我没有嗅出里面的压缩模式,同样可能不需要压缩以及解压缩阵列和工作,甚至更快!

另一个有用的是"基数"或OnesCount()

你可以设置一个256个字节的简单数组,里面的这个字节的数量(计)
把然后只需添加的所有字节(至少有4个整数加法为每个整数在_uncompressed数组)
实际的方法,使位长度的增加(循环槽)

下面是代码:
public int BitCount()

{

    CheckBitArray();

    int c = 0;

    int count = _uncompressed.Count << 2;

    for (int i = 0; i < count; i++)

    {

        c += BYTE_COUNTS[(_uncompressed[i >> 2] >> ((i & 0x3)<<3)) & 0xFF];

    }

    return c;

}
例如bitcount,也慢,连接字符串的生成在内存中的"长度"字符串,所有的分配开销。
public string Bits

{

    get

    {

        char[] c = new char[Length];

        for (int i = 0; i < Length; i++)

            c[i] = internalGet(i) ? '1' : '0';

        return new string(c);

    }

}

另外一个简单的串联并不好,但速度甚至超过的StringBuilder()为短蜇


     string s = &quot;&quot;;

     for (int i = 0; i &lt; Length; i++)

         s = (internalGet(i) ? &quot;1&quot; : &quot;0&quot;) + s;

     return s;

还需要校验,这是一个快速的方法来计算!

public bool Parity

{

    get

    {

        CheckBitArray();

        int p = 0;

        foreach (int i in _uncompressed)

            p ^= i;

        p ^= p >> 16;

        p ^= p >> 8;

        p ^= p >> 4;

        p ^= p >> 2;

        p ^= p >> 1;

        return (p & 0x01) == 0;

    }

}
和字节的计数,这里是块

#region private static byte[] BYTE_COUNTS

/// <summary>

/// Borrowed from BitSet

/// </summary>

private static byte[] BYTE_COUNTS =

{     // table of bits/byte

    0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,

    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,

    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,

    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,

    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,

    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,

    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,

    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,

    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,

    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,

    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,

    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,

    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,

    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,

    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,

    4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8

};

#endregion
希望这有助于你的一切,如果你想包含此例程,何况我与co-Author/Contributor传奇"安德烈斯Hohendahl"! {S0}
评论会员:迈赫迪吴拉姆 时间:2012/02/04
非常感谢,我会尝试的时候,我可以
中,以适应一些。其人,不是机器 - 查克耶格尔
如果一开始你没有成功...获得更好的公关
评论会员:电源 时间:2012/02/04
!很漂亮我5

对于我的应用程序,我想我会需要某种层次的访问,你看着这样的事情
评论会员:?迈赫迪吴拉姆 时间:2012/02/04
欢呼声,

你有什么想法?
其人,不是机器 - 查克耶格尔
如果一开始你没有成功...得到更好的公关
评论会员:电源 时间:2012/02/04
对不起,我不是非常清楚目前。如果您正试图以罚款超过一个巨大的基地集中的几个大集的交集,您可能需要跳到在一组或其他大的距离。这是你可能有一个集于一体,但大量的其他成员有很大的差距。我想你会需要一些层次的位阵列上的排序,以使这个快速。或者,我可能是在完全错误的方式思考这个

欢腾"
评论会员:迈赫迪吴拉姆 时间:2012/02/04
阿我看,这种实现的优点在于实际的位逻辑是由原始的BitArray。所以你不要担心。
一个有效的关注的是性能,所以您可能需要分解成大块说100mil位计算内存的可行性和性能数据集。其人,不是机器 - 查克耶格尔
如果一开始你没有成功...获得更好的公关
评论会员:SoftwareBotanyDan 时间:2012/02/04
嘿迈赫迪,

好东西。您发布的前几天我终于作出决定开源我的字对齐混合位向量的实施,我在上面建立一个搜索框架。作为一个供参考:我华载体实施的一个主要的限制是书面压缩向量只能出现显著的至少31位。检查出来:{A7}。我还需要得到更多的单元测试的代码覆盖率和文档的例子是不存在的,但是,我将会对他们的工作,以及在未来几周一系列博客文章

照顾,

评论会员:迈赫迪吴拉姆 时间:2012/02/04
。尼斯之一你确切的fastbit指令吗?它似乎是有它的专利。
RLE编码似乎很好,我有检查,以确保提交。
Personaly我的印象,这是一个"另类的主题,但人们实际上是非常有趣的方式使用它。
你有没有做任何性能测试?
其人,不是机器 - 查克耶格尔
如果一开始你没有成功...获得更好的公关
评论会员:SoftwareBotanyDan 时间:2012/02/04
关于专利的,我刚接过来一看。专利申请,使得它听起来像的压缩方案和逻辑运算都铺上。然而,FastBit是在LGPL许可(等软件植物学阳光)在序言中指出:

"最后,软件专利构成一个存在任何自由软件不断的威胁。我们确保,一个公司不能有效地限制获得一个专利持有者的限制牌照的自由软件的用户。因此,我们坚持,任何库的版本获得的专利许可必须符合本许可证规定的使用充分的自由。"

... ...后来在第11条:

"例如,如果某一专利许可证不允许所有那些通过你收到的副本直接或间接的免版税图书馆再分配,那么唯一的办法你可以同时满足该许可证将完全避免分配库中。"

所以是的,我认为它是安全的衍生作品,只要是在LGPL或GPL许可下。无论如何,我没有使用任何商业尚未的阳光。这或多或少是一种享受和机会,使用C#的类似不安全和动态特性的宠物项目。我一定要CodePlex上的警告虽然用户可能要使用商业。我也看到,如果我能得到一个人持有,谁知道如何读法律术语和诸如此类的东西。

保重,

评论会员:迈赫迪吴拉姆 时间:2012/02/04
感谢你救了我很多时间,我讨厌读法律的东西
。其人,不是机器 - 查克耶格尔
如果一开始你没有成功...获得更好的公关
评论会员:supercat9 时间:2012/02/04
SoftwareBotanyDan写道:作为一个供参考:我华载体实施的一个主要的限制是写入压缩向量只能出现显著的至少31位。
采取31位的倍数原始数据,似乎有点过甜。这似乎是一个相对简单的方法,以提高效率,将过程输出数据,在32个字,格式为31x33位的字(12​​8字节)的倍数。各组第31位将保持低32("资料"),每个逻辑输出字位,和最后一个字会举行前31个字的"模式"位。使用这种方法将允许没有0x00000000或0xFFFFFFFF以直接复制位转移或屏蔽
无需从源头到目的地的输入字
评论会员:。迈赫迪吴拉姆 时间:2012/02/04
有趣的,有关的运行和零?
其人,不是机器 - 查克耶格尔
如果一开始你没有成功...获得更好的公关
评论会员:supercat9 时间:2012/02/04
迈赫迪吴拉姆说:有趣的,怎么样运行的1和0

如果字[5]的数组应该是代表32位的文字数据,然后位字[31] 5将为零。如果Word [5]的数组应该是代表别的东西,然后位字[31] 5将设置,并表明究竟应该是字[5]位。一个非常简单的方法是使用31位表明是否这个词代表的0x00000000或0xFFFFFFFF的运行和底部的31位,表明它代表了多少这样的话。由于大多数运行是不会被任何接近2亿字的长,可能会有所帮助,让一些字位,说一些有关数据如下运行。例如,可以使用31-30位的四种类型的运行选择之一:
为0运行到零亿字
一个0运行到一个亿的话(0xFFFFFFFF的)
运行0-255位零,0-127位1的0-255的零位,0-127对位的,和足够的零垫出的任何部分的字
0-255位1的0-127的零​​位,0至255位的0-127的零​​位,和足够的垫运行任何部分字。
请注意这只是一个简单的例子,如何可以做的事情。请注意,任何四个运行,包括130位或更少(共256位或以上的四个运行的多种组合)可以存储在一个字
:基兰Sonawane
评论会员:好踢 时间:2012/02/04
迈赫迪吴拉姆: |欢呼
其人,不是机器 - 查克耶格尔
如果一开始你没有成功...获得更好的公关
评论会员:KenJohnson 时间:2012/02/04
最有趣的文章。你任何的机会,做就可以了一些性能测试。特别是,这将是很好,知道的WAHBitArray BitArray中和,或,不和XOR之间的速度差异。整数范围的申述,我一直在使用BitArrays(线段)和你的代码可能会压缩他们非常有用。所有这一切都有一些明确的潜力。
再次感谢
肯约翰逊
最新的文章{A8}
评论会员:迈赫迪吴拉姆 时间:2012/02/04
哇再次,我认为这是一个关闭击败主题,但似乎人实际上是使用bitarrays。
我永远不会猜到线段!
性能是一样的,我很害怕,因为所有的计算标准的BitArray,如果您按照fastbit网站的链接,在那里你会找到一个做了一些性能测试的研究文章。它的长和短,密度低的值的方式也比较快,但高密度的慢。

干杯
其人,不是机器 - 查克耶格尔
如果一开始你没有成功...获得更好的公关
评论会员:迈赫迪吴拉姆 时间:2012/02/04
嗨,

结帐{A9},并告诉我你的想法。
其人,不是机器 - 查克耶格尔
如果一开始你没有成功...获得更好的公关
评论会员:RugbyLeague 时间:2012/02/04
我已经有我自己在我的位数组索引压缩技术多年,但看起来要好得多。感谢。有5
评论会员:迈赫迪吴拉姆 时间:2012/02/04
哇,有人认为它是非常有用的的!! {S2} {S2} {S2}
这不是最理想的压缩技术,但它的相当快,而且它所做的研究是非常令人印象深刻的和实质性的的。
欢呼声,
其人,不是机器 - 查克耶格尔
如果一开始你没有成功...获得更好的公关
评论会员:RugbyLeague 时间:2012/02/04
好了,我没有,直到:

BitArray中RESULT1 = ba1.And(BA2)

不工作BA2是一个WAHBitArray和方法只需要一个BitArray中。

我有一个快速计数和分析数据库系统 - 这里早期版本的截图和简要介绍:{A10}

后来的版本都在内部,因此没有piccies。我一直在使用简单的RLE压缩位阵列
评论会员:。迈赫迪吴拉姆 时间:2012/02/04
我的下一个版本的某些重载

此外,我将添加的设置和自动调整大小的方法,因为它会抛出在原
例外其人,不是机器 - 查克耶格尔
如果一开始你没有成功...获得更好的公关
评论会员:迈赫迪吴拉姆 时间:2012/02/04
在不同的说明,我在如何和您使用的是位图索引和bitarrays,如果你想阐述
。其人,不是机器 - 查克耶格尔
如果一开始你没有成功...获得一个更好的公关
评论会员:RugbyLeague 时间:2012/02/04
嗨,我在一前一后在此线程的一些软件的说明

我很重写此刻这一切 - 我目前有一个编程语言C语言编写的该知道如何来谈谈标准的SQL数据库,并创建从他们的位图数据和一个图形用户界面和位图引擎彗星#和的WinForms编写使用户查询点阵数据库。

我更换一个XML的基于声明的语言的编程语言,虽然它也支持嵌入彗星#例程创建的位图数据库 - 。的图形用户界面我上午在WPF中有点痛苦重写,但我很大多有

超过12年,我有类似的系统 - 这是第5次迭代

有人解释,在科技,教育署年龄位图索引我前几个啤酒 - 我做过了自己如何实现它,并从那里去。这是我接触过议员和英国广播公司等,所以它的漂亮,从我自己的手卷东西没有从根本上不同的标准方法是近几年才。我可以在十分之一秒的计数在100万行的数据库,所以我必须做一些正确的
评论会员:。迈赫迪吴拉姆 时间:2012/02/04
伟大的工作,是新的位图索引对我太eversince项目双子座成为的PowerPivot从微软激起我兴趣极大,从而开始了旅程,找出。进入RaptorDB文件存储版本。
其人,不是机器 - 查克耶格尔
如果一开始你没有成功...获得更好的公关