公司目前存在多个系统,但是数据分散比较分散,有什么方法可以比较好的集中起来呀?

在实际的工作环境下许多人会遇到海量数据分散这个复杂而艰巨的问题,它的主要难点有以下几个方面:

一、数据分散量过大数据分散中什么情况都可能存在。

如果說有10条数据分散那么大不了每条去逐一检查,人为处理如果有上百条数据分散,也可以考虑如果数据分散上到千万级别,甚至过亿那不是手工能解决的了,必须通过工具或者程序进行处理尤其海量的数据分散中,什么情况都可能存在例如,数据分散中某处格式絀了问题尤其在程序处理时,前面还能正常处理突然到了某个地方问题出现了,程序终止了

二、软硬件要求高,系统资源占用率高

对海量的数据分散进行处理,除了好的方法最重要的就是合理使用工具,合理分配系统资源一般情况,如果处理的数据分散过TB级尛型机是要考虑的,普通的机子如果有好的方法可以考虑不过也必须加大CPU和内存,就象面对着千军万马光有勇气没有一兵一卒是很难取胜的。

三、要求很高的处理方法和技巧

这也是本文的写作目的所在,好的处理方法是一位工程师长期工作经验的积累也是个人的经驗的总结。没有通用的处理方法但有通用的原理和规则。

下面我们来详细介绍一下处理海量数据分散的经验和技巧:

一、选用优秀的数據分散库工具

现在的数据分散库工具厂家比较多对海量数据分散的处理对所使用的数据分散库工具要求比较高,一般使用Oracle或者DB2微软公司最近发布的SQL Server 2005性能也不错。另外在BI领域:数据分散库数据分散仓库,多维数据分散库数据分散挖掘等相关工具也要进行选择,象好的ETL笁具和好的OLAP工具都十分必要例如Informatic,Eassbase等笔者在实际数据分散分析项目中,对每天6000万条的日志数据分散进行处理使用SQL Server 2000需要花费6小时,而使用SQL Server 2005则只需要花费3小时

二、编写优良的程序代码

处理数据分散离不开优秀的程序代码,尤其在进行复杂数据分散处理时必须使用程序。好的程序代码对数据分散的处理至关重要这不仅仅是数据分散处理准确度的问题,更是数据分散处理效率的问题良好的程序代码应該包含好的算法,包含好的处理流程包含好的效率,包含好的异常处理机制等

三、对海量数据分散进行分区操作

对海量数据分散进行汾区操作十分必要,例如针对按年份存取的数据分散我们可以按年进行分区,不同的数据分散库有不同的分区方式不过处理机制大体楿同。例如SQL Server的数据分散库分区是将不同的数据分散存于不同的文件组下而不同的文件组存于不同的磁盘分区下,这样将数据分散分散开减小磁盘I/O,减小了系统负荷而且还可以将日志,索引等放于不同的分区下

对海量的数据分散处理,对大表建立索引是必行的建立索引要考虑到具体情况,例如针对大表的分组、排序等字段都要建立相应索引,一般还可以建立复合索引对经常插入的表则建立索引時要小心,笔者在处理数据分散时曾经在一个ETL流程中,当插入表时首先删除索引,然后插入完毕建立索引,并实施聚合操作聚合唍成后,再次插入前还是删除索引所以索引要用到好的时机,索引的填充因子和聚集、非聚集索引都要考虑

当数据分散量增加时,一般的处理工具都要考虑到缓存问题缓存大小设置的好差也关系到数据分散处理的成败,例如笔者在处理2亿条数据分散聚合操作时,缓存设置为100000条/Buffer这对于这个级别的数据分散量是可行的。

如果系统资源有限内存提示不足,则可以靠增加虚拟内存来解决笔者在实际项目中曾经遇到针对18亿条的数据分散进行处理,内存为1GB1个P42.4G的CPU,对这么大的数据分散量进行聚合操作是有问题的提示内存不足,那么采用叻加大虚拟内存的方法来解决在6块磁盘分区上分别建立了6个4096M的磁盘分区,用于虚拟内存这样虚拟的内存则增加为 4096*6 + M,解决了数据分散处悝中的内存不足问题

海量数据分散处理难因为数据分散量大,那么解决海量数据分散处理难的问题其中一个技巧是减少数据分散量可鉯对海量数据分散分批处理,然后处理后的数据分散再进行合并操作这样逐个击破,有利于小数据分散量的处理不至于面对大数据分散量带来的问题,不过这种方法也要因时因势进行如果不允许拆分数据分散,还需要另想办法不过一般的数据分散按天、按月、按年等存储的,都可以采用先分后合的方法对数据分散进行分开处理。

八、使用临时表和中间表

数据分散量增加时处理中要考虑提前汇总。这样做的目的是化整为零大表变小表,分块处理完成后再利用一定的规则进行合并,处理过程中的临时表的使用和中间结果的保存嘟非常重要如果对于超海量的数据分散,大表处理不了只能拆分为多个小表。如果处理过程中需要多步汇总操作可按汇总步骤一步步来,不要一条语句完成一口气吃掉一个胖子。

九、优化查询SQL语句

在对海量数据分散进行查询处理过程中查询的SQL语句的性能对查询效率的影响是非常大的,编写高效优良的SQL脚本和存储过程是数据分散库工作人员的职责也是检验数据分散库工作人员水平的一个标准,在對SQL语句的编写过程中例如减少关联,少用或不用游标设计好高效的数据分散库表结构等都十分必要。笔者在工作中试着对1亿行的数据汾散使用游标运行3个小时没有出结果,这是一定要改用程序处理了

十、使用文本格式进行处理

对一般的数据分散处理可以使用数据分散库,如果对复杂的数据分散处理必须借助程序,那么在程序操作数据分散库和程序操作文本之间选择是一定要选择程序操作文本的,原因为:程序操作文本速度快;对文本进行处理不容易出错;文本的存储不受限制等例如一般的海量的网络日志都是文本格式或者csv格式(文本格式),对它进行处理牵扯到数据分散清洗是要利用程序进行处理的,而不建议导入数据分散库再做清洗

十一、定制强大的清洗规则和出错处理机制

海量数据分散中存在着不一致性,极有可能出现某处的瑕疵例如,同样的数据分散中的时间字段有的可能为非标准的时间,出现的原因可能为应用程序的错误系统的错误等,这是在进行数据分散处理时必须制定强大的数据分散清洗规则和出錯处理机制。

十二、建立视图或者物化视图

视图中的数据分散来源于基表对海量数据分散的处理,可以将数据分散按一定的规则分散到各个基表中查询或处理过程中可以基于视图进行,这样分散了磁盘I/O正如10根绳子吊着一根柱子和一根吊着一根柱子的区别。

十三、避免使用32位机子(极端情况)

目前的计算机很多都是32位的那么编写的程序对内存的需要便受限制,而很多的海量数据分散处理是必须大量消耗内存的这便要求更好性能的机子,其中对位数的限制也十分重要

十四、考虑操作系统问题

海量数据分散处理过程中,除了对数据分散库处理程序等要求比较高以外,对操作系统的要求也放到了重要的位置一般是必须使用服务器的,而且对系统的安全性和稳定性等偠求也比较高尤其对操作系统自身的缓存机制,临时空间的处理等问题都需要综合考虑

十五、使用数据分散仓库和多维数据分散库存儲

数据分散量加大是一定要考虑OLAP的,传统的报表可能5、6个小时出来结果而基于Cube的查询可能只需要几分钟,因此处理海量数据分散的利器昰OLAP多维分析即建立数据分散仓库,建立多维数据分散集基于多维数据分散集进行报表展现和数据分散挖掘等。

十六、使用采样数据分散进行数据分散挖掘

基于海量数据分散的数据分散挖掘正在逐步兴起,面对着超海量的数据分散一般的挖掘软件或算法往往采用数据汾散抽样的方式进行处理,这样的误差不会很高大大提高了处理效率和处理的成功率。一般采样时要注意数据分散的完整性和防止过夶的偏差。笔者曾经对1亿2千万行的表数据分散进行采样抽取出400万行,经测试软件测试处理的误差为千分之五客户可以接受。

还有一些方法需要在不同的情况和场合下运用,例如使用代理键等操作这样的好处是加快了聚合时间,因为对数值型的聚合比对字符型的聚合赽得多类似的情况需要针对不同的需求进行处理。

海量数据分散是发展趋势对数据分散分析和挖掘也越来越重要,从海量数据分散中提取有用信息重要而紧迫这便要求处理要准确,精度要高而且处理时间要短,得到有价值信息要快所以,对海量数据分散的研究很囿前途也很值得进行广泛深入的研究。

  大数据分散量的问题是很多面试笔试中经常出现的问题比如baidu google 腾讯 这样的一些涉及到海量数據分散的公司经常会问到。

  下面的方法是我对海量数据分散的处理方法进行了一个一般性的总结当然这些方法可能并不能完全覆盖所有的问题,但是这样的一些方法也基本可以处理绝大多数遇到的问题下面的一些问题基本直接来源于公司的面试笔试题目,方法不一萣最优如果你有更好的处理方法,欢迎与我讨论

  本贴从解决这类问题的方法入手,开辟一系列专题来解决海量数据分散问题拟包含 以下几个方面。

  在这些解决方案之上再借助一定的例子来剖析海量数据分散处理问题的解决方案。

Bloom Filter是一种空间效率很高的随机數据分散结构它利用位数组很简洁地表示一个集合,并能判断一个元素是否属于这个集合Bloom Filter的这种高效是有一定代价的:在判断一个元素是否属于某个集合时,有可能会把不属于这个集合的元素误认为属于这个集合(false positive)因此,Bloom Filter不适合那些“零错误”的应用场合而在能嫆忍低错误率的应用场合下,Bloom Filter通过极少的错误换取了存储空间的极大节省 这里有一篇关于Bloom Filter的详细介绍,不太懂的博友可以看看 
可以用來实现数据分散字典,进行数据分散的判重或者集合求交集 
【基本原理及要点】 
对于原理来说很简单,位数组+k个独立hash函数将hash函数对应嘚值的位数组置1,查找时如果发现所有hash函数对应位都是1说明存在很明显这 个过程并不保证查找的结果是100%正确的。同时也不支持删除一个巳经插入的关键字因为该关键字对应的位会牵动到其他的关键字。所以一个简单的改进就是 counting Bloom filter用一个counter数组代替位数组,就可以支持删除叻 

还有一个比较重要的问题,如 何根据输入元素个数n确定位数组m的大小及hash函数个数。当hash函数个数k=(ln2)*(m/n)时错误率最小在错误率不大于E的情況 下,m至少要等于n*lg(1/E)才能表示任意n个元素的集合但m还应该更大些,因为还要保证bit数组里至少一半为0则m应 该>=nlg(1/E)*lge

举个例子我们假设错误率为0.01,則此时m应大概是n的13倍这样k大概是8个。 

注意这里m与n的单位不同m是bit为单位,而n则是以元素个数为单位(准确的说是不同元素的个数)通常单個元素的长度都是有很多bit的。所以使用bloom filter内存上通常都是节省的 


Bloom filter将集合中的元素映射到位数组中,用k(k为哈希函数个数)个映射位是否全1表示元素在不在这个集合中Counting bloom filter(CBF)将位数组中的每一位扩展为一个counter,从而支持了元素的删除操作Spectral Bloom Filter(SBF)将其与集合元素的出现次数关联。SBF采用counter中的最小值来近似表示元素的出现频率 
给你A,B两个文件,各存放50亿条URL每条URL占用64字节,内存限制是4G让你找出A,B文件共同的URL。如果是三個乃至n个文件呢 

根据这个问题我们来计算下内存的占用,4G=2^32大概是40亿*8大概是340亿bitn=50亿,如果按出错率0.01算需要的大概是650亿个bit 现在可用的是340亿,相差并不多这样可能会使出错率上升些。另外如果这些urlip是一一对应的就可以转换成ip,则大大简单了


  Hash,一般翻译做“散列”也有矗接音译为“哈希”的,就是把任意长度的输入(又叫做预映射 pre-image),通过散列算法变换成固定长度的输出,该输出就是散列值这种轉换是一种压缩映射,也就是散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出而不可能从散列值来唯一的確定输入值。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数 
HASH主要用于信息安全领域中加密算法,它把一些鈈同长度的信息转化成杂乱的128位的编码,这些编码值叫做HASH值. 也可以说hash就是找到一种数据分散内容和数据分散存放地址之间的映射关系。 
  数組的特点是:寻址容易插入和删除困难;而链表的特点是:寻址困难,插入和删除容易那么我们能不能综合两者的特性,做出一种寻址容易插入删除也容易的数据分散结构?答案是肯定的这就是我们要提起的哈希表,哈希表有多种不同的实现方法我接下来解释的昰最常用的一种方法——拉链法,我们可以理解为“链表的数组”如图: 


左边很明显是个数组,数组的每个成员包括一个指针指向一個链表的头,当然这个链表可能为空也可能元素很多。我们根据元素的一些特征把元素分配到不同的链表中去也是根据这些特征,找箌正确的链表再从链表中找出这个元素。 
元素特征转变为数组下标的方法就是散列法散列法当然不止一种,下面列出三种比较常用的 
最直观的一种,上图使用的就是这种散列法公式: 
学过汇编的都知道,求模数其实是通过一个除法运算得到的所以叫“除法散列法”。 
求index是非常频繁的操作而乘法的运算要比除法来得省时(对现在的CPU来说,估计我们感觉不出来)所以我们考虑把除法换成乘法和一個位移操作。公式: 
如果数值分配比较均匀的话这种方法能得到不错的结果但我上面画的那个图的各个元素的值算出来的index都是0——非常夨败。也许你还有个问题value如果很大,value * value不会溢出吗答案是会的,但我们这个乘法不关心溢出因为我们根本不是为了获取相乘结果,而昰为了获取index 
平方散列法的缺点是显而易见的,所以我们能不能找出一个理想的乘数而不是拿value本身当作乘数呢?答案是肯定的 
2,对于32位整数而言这个乘数是 
3,对于64位整数而言这个乘数是 
这几个“理想乘数”是如何得出来的呢?这跟一个法则有关叫黄金分割法则,洏描述黄金分割法则的最经典表达式无疑就是著名的斐波那契数列如果你还有兴趣,就到网上查找一下“斐波那契数列”等关键字我數学水平有限,不知道怎么描述清楚为什么另外斐波那契数列的值居然和太阳系八大行星的轨道半径的比例出奇吻合,很神奇对么?
對我们常见的32位整数而言公式: 
如果用这种斐波那契散列法的话,那我上面的图就变成这样了: 


很明显用斐波那契散列法调整之后要仳原来的取摸散列法好很多。 
快速查找删除的基本数据分散结构,通常需要总数据分散量可以放入内存 
【基本原理及要点】 
hash函数选择,针对字符串整数,排列具体相应的hash方法。 
d-left hashing中的d是多个的意思我们先简化这个问题,看一看2-left hashing2-left hashing指的是将一个哈希表分成长度相等的兩半,分别叫做T1和T2给T1和T2分别配备一个哈希函数,h1和h2在存储一个新的key时,同 时用两个哈希函数进行计算得出两个地址h1[key]和h2[key]。这时需要检查T1中的h1[key]位置和T2中的h2[key]位置哪一个 位置已经存储的(有碰撞的)key比较多,然后将新key存储在负载少的位置如果两边一样多,比如两个位置都為空或者都存储了一个key就把新key 存储在左边的T1子表中,2-left也由此而来在查找一个key时,必须进行两次hash同时查找两个位置。 
1).海量日志数据分散提取出某日访问百度次数最多的那个IP。 
IP的数目还是有限的最多2^32个,所以可以考虑使用hash将ip直接存入内存然后进行统计。

所谓的Bit-map就是鼡一个bit位来标记某个元素对应的Value 而Key即是该元素。由于采用了Bit为单位来存储数据分散因此在存储空间方面,可以大大节省 
如果说了这麼多还没明白什么是Bit-map,那么我们来看一个具体的例子假设我们要对0-7内的5个元素(4,7,2,5,3)排序(这里假设这些元素没有重复)。那么我们就可以采鼡Bit-map的方法来达到排序的目的要表示8个数,我们就只需要8个Bit(1Bytes)首先我们开辟1Byte的空间,将这些空间的所有Bit位都置为0(如下图:) 


然后遍历这5個元素首先第一个元素是4,那么就把4对应的位置为1(可以这样操作 p+(i/8)|(0x01<<(i%8)) 当然了这里的操作涉及到Big-ending和Little-ending的情况这里默认为Big-ending),因为是从零开始的,所以要把第五位置为一(如下图): 


然后再处理第二个元素7将第八位置为1,,接着再处理第三个元素一直到最后处理完所有的元素,將相应的位置为1这时候的内存的Bit位的状态如下: 


然后我们现在遍历一遍Bit区域,将该位是一的位的编号输出(23,45,7)这样就达到了排序的目的。下面的代码给出了一个BitMap的用法:排序 

 
  



可进行数据分散的快速查找,判重删除,一般来说数据分散范围是int的10倍以下

使用bit数組来表示某些元素是否存在比如8位电话号码



1)已知某个文件内包含一些电话号码,每个号码为8位数字统计不同号码的个数。
8位最多99 999 999大概需要99m个bit,大概10几m字节的内存即可 (可以理解为从0-99 999 999的数字,每个数字对应一个Bit位所以只需要99M个Bit==1.2MBytes,这样就用了小小的1.2M左右的内存表示叻所有的8位数的电话)
2)2.5亿个整数中找出不重复的整数的个数,内存空间不足以容纳这2.5亿个整数
将bit-map扩展一下,用2bit表示一个数即可0表示未絀现,1表示出现一次2表示出现2次及以上,在遍历这些数的时候如果对应位置的值是0,则将其置为1;如果是1将其置为2;如果是2,则保歭不变或者我们不用2bit来进行表示,我们用两个bit-map即可模拟实现这个2bit-map都是一样的道理。
【什么是堆】
概念:堆是一种特殊的二叉树具备鉯下两种性质
1)每个节点的值都大于(或者都小于,称为最小堆)其子节点的值
2)树是完全平衡的并且最后一层的树叶都在最左边
这样僦定义了一个最大堆。如下图用一个数组来表示堆:

那么下面介绍二叉堆:二叉堆是一种完全二叉树其任意子树的左右节点(如果有的話)的键值一定比根节点大,上图其实就是一个二叉堆
你一定发觉了,最小的一个元素就是数组第一个元素那么二叉堆这种有序队列洳何入队呢?看图:

假设要在这个二叉堆里入队一个单元键值为2,那只需在数组末尾加入这个元素然后尽可能把这个元素往上挪,直箌挪不动经过了这种复杂度为Ο(logn)的操作,二叉堆还是二叉堆
那如何出队呢?也不难看图:


出队一定是出数组的第一个元素,这么来苐一个元素以前的位置就成了空位我们需要把这个空位挪至叶子节点,然后把数组最后一个元素插入这个空位把这个“空位”尽量往仩挪。这种操作的复杂度也是Ο(logn)
【适用范围】
海量数据分散前n大,并且n比较小堆可以放入内存
【基本原理及要点】
最大堆求前n小,最尛堆求前n大方法,比如求前n小我们比较当前元素与最大堆里的最大元素,如果它小于最大元素则应该替换那个最大元 素。这样最后嘚到的n个元素就是最小的n个适合大数据分散量,求前n小n的大小比较小的情况,这样可以扫描一遍即可得到所有的前n元素效率很高。
【扩展】
双堆一个最大堆与一个最小堆结合,可以用来维护中位数
【问题实例】
1)100w个数中找最大的前100个数。
用一个100个元素大小的最小堆即可
【什么是双层桶】 事实上,与其说双层桶划分是一种数据分散结构不如说它是一种算法设计思想。面对一堆大量的数据分散我们無法处理的时候我们可以将其分成一个个小的单元,然后根据一定的策略来处理这些小单元从而达到目的。
【适用范围】 第k大中位數,不重复或重复的数字
【基本原理及要点】 因为元素范围很大不能利用直接寻址表,所以通过多次划分逐步确定范围,然后最后在┅个可以接受的范围内进行可以通过多次缩小,双层只是一个例子分治才是其根本(只是“只分不治”)。
【扩展】 当有时候需要用┅个小范围的数据分散来构造一个大数据分散也是可以利用这种思想,相比之下不同的只是其中的逆过程。
【问题实例】
1).2.5亿个整数中找出不重复的整数的个数内存空间不足以容纳这2.5亿个整数。

有 点像鸽巢原理整数个数为2^32,也就是,我们可以将这2^32个数划分为2^8个区域(比洳用单个文件代表一个区域),然后将数据分散分离到不同的区 域然后不同的区域在利用bitmap就可以直接解决了。也就是说只要有足够的磁盘涳间就可以很方便的解决。 当然这个题也可以用我们前面讲过的BitMap方法解决正所谓条条大道通罗马~~~
2).5亿个int找它们的中位数。
这个例子比上媔那个更明显首先我们将int划分为2^16个区域,然后读取数据分散统计落到各个区域里的数的个数之后我们根据统计结果就可以判断中位数落到那个区域,同时知道这个区域中的第几大数刚好是中位数然后第二次扫描我们只统计落在这个区域中的那些数就可以了。
实 际上洳果不是int是int64,我们可以经过3次这样的划分即可降低到可以接受的程度即可以先将int64分成2^24个区域,然后确定区域的第几 大数在将该区域分荿2^20个子区域,然后确定是子区域的第几大数然后子区域里的数的个数只有2^20,就可以直接利用direct addr table进行统计了
3).现在有一个0-30000的随机数生成器。請根据这个随机数生成器设计一个抽奖范围是0-350000彩票中奖号码列表,其中要包含20000个中奖号码
这个题刚好和上面两个思想相反,一个0到3万嘚随机数生成器要生成一个0到35万的随机数那么我们完全可以将0-35万的区间分成35/3=12个区 间,然后每个区间的长度都小于等于3万这样我们就可鉯用题目给的随机数生成器来生成了,然后再加上该区间的基数那么要每个区间生成多少个随机数呢?计 算公式就是:区间长度*随机数密度在本题目中就是30000*()。最后要注意一点该题目是有隐含条件的:彩票,这意味着你 生成的随机数里面不能有重复这也是我为什麼用双层桶划分思想的另外一个原因。
索引是对数据分散库表中一列或多列的值进行排序的一种结构使用索引可快速访问数据分散库表Φ的特定信息。
  
 
  
 
  数据分散库索引好比是一本书前面的目录能加快数据分散库的查询速度。
  例如这样一个查询:select * from table1 where id=44如果没有索引,必须遍历整个表直到ID等于44的这一行被找到为止;有了索引之后(必须是在ID这一列上建立的索引),直接在索引里面找44(也就是在ID这一列找)就可以得知这一行的位置,也就是找到了这一行可见,索引是用来定位的
  索引分为聚簇索引和非聚簇索引两种,聚簇索引 是按照数据分散存放的物理位置为顺序的而非聚簇索引就不一样了;聚簇索引能提高多行检索的速度,而非聚簇索引对于单行的检索很快
  
 
  建立索引的目的是加快对表中记录的查找或排序。
  为表设置索引要付出代价的:一是增加了数据分散库的存储空间二是在插叺和修改数据分散时要花费较多的时间(因为索引也要随之变动)。

  
 
  创建索引可以大大提高系统的性能
    第一,通过创建唯一性索引可以保证数据分散库表中每一行数据分散的唯一性。
    第二可以大大加快数据分散的检索速度,这也是创建索引的最主要嘚原因
    第三,可以加速表和表之间的连接特别是在实现数据分散的参考完整性方面特别有意义。
    第四在使用分组囷排序子句进行数据分散检索时,同样可以显著减少查询中分组和排序的时间
    第五,通过使用索引可以在查询的过程中,使鼡优化隐藏器提高系统的性能。
  也许会有人要问:增加索引有如此多的优点为什么不对表中的每一个列创建一个索引呢?因为增加索引也有许多不利的方面。
    第一创建索引和维护索引要耗费时间,这种时间随着数据分散量的增加而增加
    第二,索引需要占物理空间除了数据分散表占数据分散空间之外,每一个索引还要占一定的物理空间如果要建立聚簇索引,那么需要的空間就会更大
    第三,当对表中的数据分散进行增加、删除和修改的时候索引也要动态的维护,这样就降低了数据分散的维护速喥
  
 
  索引是建立在数据分散库表中的某些列的上面。在创建索引的时候应该考虑在哪些列上可以创建索引,在哪些列上不能创建索引一般来说,应该在这些列上创建索引:
  在经常需要搜索的列上可以加快搜索的速度;
  在作为主键的列上,强制该列的唯一性和组织表中数据分散的排列结构;
  在经常用在连接的列上这些列主要是一些外键,可以加快连接的速度;在经常需要根据范围进荇搜索的列上创建索引因为索引已经排序,其指定的范围是连续的;
  在经常需要排序的列上创建索引因为索引已经排序,这样查詢可以利用索引的排序加快排序查询时间;
  在经常使用在WHERE子句中的列上面创建索引,加快条件的判断速度
  同样,对于有些列鈈应该创建索引一般来说,不应该创建索引的的这些列具有下列特点:
  第一对于那些在查询中很少使用或者参考的列不应该创建索引。这是因为既然这些列很少使用到,因此有索引或者无索引并不能提高查询速度。相反由于增加了索引,反而降低了系统的维護速度和增大了空间需求
  第二,对于那些只有很少数据分散值的列也不应该增加索引这是因为,由于这些列的取值很少例如人倳表的性别列,在查询的结果中结果集的数据分散行占了表中数据分散行的很大比例,即需要在表中搜索的数据分散行的比例很大增加索引,并不能明显加快检索速度
  第三,对于那些定义为text, image和bit数据分散类型的列不应该增加索引这是因为,这些列的数据分散量要麼相当大要么取值很少,不利于使用索引。
  第四当修改性能远远大于检索性能时,不应该创建索引这是因为,修改性能和检索性能是互相矛盾的当增加索引时,会提高检索性能但是会降低修改性能。当减少索引时会提高修改性能,降低检索性能因此,当修妀操作远远多于检索操作时不应该创建索引。
  
 
  此外除了数据分散库索引之外,在LAMP结果如此流行的今天数据分散库(尤其是MySQL)性能优化也是海量数据分散处理的一个热点。下面就结合自己的经验聊一聊MySQL数据分散库优化的几个方面。
  首先在数据分散库设计的時候,要能够充分的利用索引带来的性能提升至于如何建立索引,建立什么样的索引在哪些字段上建立索引,上面已经讲的很清楚了这里不在赘述。另外就是设计数据分散库的原则就是尽可能少的进行数据分散库写操作(插入更新,删除等)查询越简单越好。如丅:



  其次配置缓存是必不可少的,配置缓存可以有效的降低数据分散库查询读取次数从而缓解数据分散库服务器压力,达到优化嘚目的一定程度上来讲,这算是一个“围魏救赵”的办法可配置的缓存包括索引缓存(key_buffer),排序缓存(sort_buffer)查询缓存(query_buffer),表描述符缓存(table_cache)如下图:


  第三,切表切表也是一种比较流行的数据分散库优化法。分表包括两种方式:横向分表和纵向分表其中,横向分表比较有使用意义故名思议,横向切表就是指把记录分到不同的表中而每条记录仍旧是完整的(纵向切表后每条记录是不完整的),例如原始表中囿100条记录我要切成2个表,那么最简单也是最常用的方法就是ID取摸切表法本例中,就把ID为1,3,5,7。的记录存在一个表中,ID为2,4,6,8,。的记录存在另一张表中。虽然横向切表可以减少查询强度但是它也破坏了原始表的完整性,如果该表的统计操作比较多那么就不适合横向切表。横向切表有个非常典型的用法就是用户数据分散:每个用户的用户数据分散一般都比较庞大,但是每个用户数据分散之间的关系不夶因此这里很适合横向切表。最后要记住一句话就是:分表会造成查询的负担,因此在数据分散库设计之初要想好是否真的适合切表的优化:


第四,日志分析在数据分散库运行了较长一段时间以后,会积累大量的LOG日志其实这里面的蕴涵的有用的信息量还是很大的。通过分析日志可以找到系统性能的瓶颈,从而进一步寻找优化方案


以上讲的都是单机MySQL的性能优化的一些经验,但是随着信息大爆炸单机的数据分散库服务器已经不能满足我们的需求,于是多多节点,分布式数据分散库网络出现了其一般的结构如下:


这种分布式集群的技术关键就是“同步复制”。。
在信息大爆炸的今天有了搜索引擎的帮助,使得我们能够快速便捷的找到所求。提到搜索引擎就不得不说VSM模型,说到VSM就不得不聊倒排索引。可以毫不夸张的讲倒排索引是搜索引擎的基石。
VSM全称是Vector Space Model(向量空间模型)是IR(Information Retrieval信息检索)模型中的一种,由于其简单直观,高效所以被广泛的应用到搜索引擎的架构中。98年的Google就是凭借这样的一个模型开始了它的疯狂扩张の路。废话不多说让我们来看看到底VSM是一个什么东东。
在开始之前我默认大家对线性代数里面的向量(Vector)有一定了解的。向量是既有大小叒有方向的量通常用有向线段表示,向量有:加、减、倍数、内积、距离、模、夹角的运算
文档(Document):一个完整的信息单元,对应的搜索引擎系统里就是指一个个的网页。
标引项(Term):文档的基本构成单位例如在英文中可以看做是一个单词,在中文中可以看作一个词语
查詢(Query):一个用户的输入,一般由多个Term构成
那么用一句话概况搜索引擎所做的事情就是:对于用户输入的Query,找到最相似的Document返回给用户而这囸是IR模型所解决的问题:
信息检索模型是指如何对查询和文档进行表示,然后对它们进行相似度计算的框架和方法

现在有两篇文章(Document)分别昰 “春风来了,春天的脚步近了” 和 “春风不度玉门关”然后输入的Query是“春风”,从直观上感觉前者和输入的查询更相关一些,因为咜包含有2个春但这只是我们的直观感觉,如何量化呢要知道计算机是门严谨的学科^_^。这个时候我们前面讲的Term和VSM模型就派上用场了。
艏先我们要确定向量的维数这时候就需要一个字典库,字典库的大小即是向量的维数。在该例中字典为{春风,来了,春天, 的,脚步,近了,不喥,玉门关} ,文档向量查询向量如下图:


PS:为了简单起见,这里分词的粒度很大
将Query和Document都量化为向量以后,那么就可以计算用户的查询和哪個文档相似性更大了简单的计算结果是D1和D2同Query的内积都是1,囧当然了,如果分词粒度再细一些查询的结果就是另外一个样子了,因此汾词的粒度也是会对查询结果(主要是召回率和准确率)造成影响的
上述的例子是用一个很简单的例子来说明VSM模型的,计算文档相似度嘚时候也是采用最原始的内积的方法并且只考虑了词频(TF)影响因子,而没有考虑反词频(IDF)而现在比较常用的是cos夹角法,影响因子也非常多据传Google的影响因子有100+之多。
大名鼎鼎的Lucene项目就是采用VSM模型构建的VSM的核心公式如下(由cos夹角法演变,此处省去推导过程)


从上面的例子不難看出如果向量的维度(对汉语来将,这个值一般在30w-45w)变大而且文档数量(通常都是海量的)变多,那么计算一次相关性开销是非常大的,洳何解决这个问题呢不要忘记了我们这节的主题就是 倒排索引,主角终于粉墨登场了!!!
倒排索引非常类似我们前面提到的Hash结构以丅内容来自维基百科:
倒排索引(英语:Inverted index),也常被称为反向索引置入档案反向档案是一种索引方法,被用来存储在全文搜索下某個单词在一个文档或者一组文档中的存储位置的映射它是文档检索系统中最常用的数据分散结构。
有两种不同的反向索引形式:
  
  • 一条记錄的水平反向索引(或者反向档案索引)包含每个引用单词的文档的列表
  • 一个单词的水平反向索引(或者完全反向索引)又包含每个单詞在一个文档中的位置。
  
 
后者的形式提供了更多的兼容性(比如短语搜索)但是需要更多的时间和空间来创建。
由上面的定义可以知道一个倒排索引包含一个字典的索引和所有词的列表。其中字典索引中包含了所有的Term(通俗理解为文档中的词)索引后面跟的列表则保存该詞的信息(出现的文档号,甚至包含在每个文档中的位置信息)下面我们还采用上面的方法举一个简单的例子来说明倒排索引。
例如现在我們要对三篇文档建立索引(实际应用中文档的数量是海量的):
文档1(D1):中国移动互联网发展迅速
文档2(D2):移动互联网未来的潜力巨大
文档3(D3):中華民族是个勤劳的民族
那么文档中的词典集合为:{中国,移动互联网,发展迅速,未来的,潜力巨大,中华民族,是个,勤勞}



在上面的索引中存储了两个信息,文档号和出现的次数建立好索引以后,我们就可以开始查询了例如现在有一个Query是”中国移动”。首先分词得到Term集合{中国移动},查倒排索引分别计算query和d1,d2,d3的距离。有没有发现倒排表建立好以后,就不需要在检索整个文档库而是矗接从字典集合中找到“中国”和“移动”,然后遍历后面的列表直接计算
对倒排索引结构我们已经有了初步的了解,但在实际应用中還有些需要解决的问题(主要是由海量数据分散引起的)笔者列举一些问题,并给出相应的解决方案抛砖以引玉,希望大家可以展开讨论:
1.左侧的索引表如何建立?怎么做才能最高效
可能有人不假思索回答:左侧的索引当然要采取hash结构啊,这样可以快速的定位到字典项但昰这样问题又来了,hash函数如何选取呢而且hash是有碰撞的,但是倒排表似乎又是不允许碰撞的存在的事实上,虽然倒排表和hash异常的相思泹是两者还是有很大区别的,其实在这里我们可以采用前面提到的Bitmap的思想每个Term(单词)对应一个位置(当然了,这里不是一个比特位)而且是┅一对应的。如何能够做到呢一般在文字处理中,有很多的编码汉字中的GBK编码基本上就可以包含所有用到的汉字,每个汉字的GBK编码是確定的因此一个Term的”ID”也就确定了,从而可以做到快速定位注:得到一个汉字的GBK号是非常快的过程,可以理解为O(1)的时间复杂度
2.如何赽速的添加删除更新索引?
有经验的码农都知道一般在系统的“做加法”的代价比“做减法”的代价要低很多,在搜索引擎中中也不例外因此,在倒排表中遇到要删除一个文档,其实不是真正的删除而是将其标记删除。这样一个减法操作的代价就比较小了
3.那么多嘚海量文档,如果存储呢有么有什么备份策略呢?
当然了一台机器是存储不下的,分布式存储是采取的一般的备份保存3份就足够了。
好了倒排索引终于完工了,不足的地方请指正谢谢

我要回帖

更多关于 数据分散 的文章

 

随机推荐