Lucene

GeoHash: "经度,纬度,经度,纬度,..." 交替编码,经度[-180, +180]首次划分为"[-180,0)编码为0"和"[0,+180]编码为1",纬度[-90,+90]首次划分为"[-90,0)编码为0"和"[0,+90]编码为1";大体上,2个geohash的前缀相同的位数越多,距离约近些;前缀相同的位数,决定了他们落在了哪一个块里面。

 

Lucene: 词典文件(存放keyword),频率文件(存放文章ID和出现次数),位置文件(存放offset);

词典文件用了压缩:<前缀长度,后缀内容>;  比如前一个词是“阿拉伯”,当前词为“阿拉伯语”,存储为<3,语>;

频率文件用了数字压缩:上一个文章ID是16382,当前文章ID是16389,则当前只存储7;

 

SimHash: 可以度量相似文本(不仅仅是相同文本);Hamming距离度量相似度(也就是XOR之后的1的个数)

步骤:1.分词,求权重;2.每个词得到64位哈希值;3.每个词的哈希值进行正负化(0变成-1,1变成1)乘以词权重,所有词的结果向量相加;4.总结果进行二值化(负数对应0,整数对应1),得到该段文本的SimHash值;

海量数据场景下:按照抽屉原理,把64位的SimHash分成4段,两个SimHash之间如果有最多3段不同,则必有一段是相同的;对每一段,建立一份倒排索引表(共4份倒排索引表);查找相似时,来一个Query的SimHash,把它的每一段作为Key,到相应的倒排索引表里,查找再该段上和它相同的候选SimHash们,过滤掉其中另3段的总Hamming距离大于3的;

分布式系统场景下:可用Map-Reduce;可一次处理一批查询(比如1MB左右);所有SimHash被分成很多小块(比如每块64MB);每个Mapper处理一个小块;每个Mapper把这批查询加载至内存,然后顺序从磁盘上读64MB这个块,对每条数据,产出<输入查询SimHash, 目标SimHash>这样的pair(可能一个SimHash产出多条); Reducer负责聚合,(如果原始文件有重复,则这里需要去重)

FingerPrint(网页的指纹): 1.网页分词,用同义词词典进行替换(替换成key);2.TF-IDF计算,把名次的权重调高些;3.词向量按权重排名,取前n个;4.调用MD5算法对"排序后的前n个词组成的字符串"进行编码,得到FingerPrint

 

关键词提取:

1. TF-IDF;

2. TextRank;

3. 利用位置信息:开始和结束位置的词一般更重要;首段和尾段里的词一般更重要;

4. 标题里的词往往比内容更重要!

5. 名词或名词结尾的词,往往更重要;

6. 利用词或字的互信息:比如I(福, 娃)=log[p(福,娃)/(p(福)p(娃))]   (也就是,福和娃经常一起出现,福和娃单个字很少在其他地方出现)

7. 《》和“”内部的词很可能是关键词;

8. 把出现的名词按照语义聚类,聚类中心作关键词;

9. H1标签和<B>加粗标签,里面的内容往往更重要;

 

相关搜索词:(搜索提示词)

1. 可用编辑距离计算相似词组;

2. 可用用户搜索日志,把一个用户一次session里的词作为一组,经常在同组出现的pair就可能是相关词;

3. 根据上下文共现的隐语义模型

 

拼写纠错:

又见贝叶斯公式:p(correct|wrong) = p(wrong|correct) * p(correct) / p(wrong);分母可以消去,所以取决于似然概率p(wrong|correct)和先验概率p(correct)

Levenshtein自动机:把词典用Trie树表示,然后把这棵树建成Levenshtein自动机(对每个词可以接受最多n个拼写错误);然后把查询串放到该自动机里遍历即可,遍历完查询串时到达的所有可接受状态,就是可模糊匹配的单词;

可能产生拼写错误的:字形相似,发音相似

 

自动生成摘要:(摘取性,概括性;前者从原文摘出重要的句子,好实现)

1.统计关键词(可结合TF/IDF, 词性,依存关系加权中心词,去停用词);

2.把内容拆分成句子;

3.通过各句关键词出现的情况定义各句子的重要度(可考虑首段尾段,段首段尾,重要度加大)(陈述句比疑问句和感叹句的重要度大)(线索词会对所在句子加分或者减分,比如“总而言之”“综上所述”是加分;“比如”“例如”是减分);

4.确定前k个句子为文摘句;(可动态调整句子重要度,即考虑句子之间的冗余度;先找出第1重要的句子,其他句子和它计算相似度,相似度越大减分越多,然后这N-1个句子按重要度排序,选出第2重要的句子,以此类推)(调整关联句的权重,给更重要的句子加权;如果关联句只剩一半,则去掉句首关联词;关联句:“虽然”..."但是"(加权后半句), "比如"(前面句子如果不是摘要句,则本句减权))

5.将文摘句按照原文中的顺序进行输出;

 

识别是不是邮件的特征提取:只把名词和动词做特征;其他非词向量的特征:看标题里是否包含“来自...”“致...”,内容结束处是否有日期和问候语等;

特征选择:

CHI卡方检测:某个词A,用"该类包含A的文档数"a,"非该类包含A的文档数"b, "该类不包含A的文档数"c, "非该类不包含A的文档数"d,n=a+b+c+d, 四个数的卡方值=[n*(ad-bc)^2] / [(a+c)*(a+b)*(d+c)*(d+b)];  (分子用了平方,所以正相关和负相关大的都会排在前面)

CHI卡方检测缺点:它只统计文档是否出现词,而不管出现了几次。这会使得他对低频词有所偏袒(因为它夸大了低频词的作用)。甚至会出现有些情况,一个词在一类文章的每篇文档中都只出现了一次,其开方值却大过了在该类文章99%的文档中出现了10次的词,其实后面的词才是更具代表性的,但只因为它出现的文档数比前面的词少了“1”,特征选择的时候就可能筛掉后面的词而保留了前者。这就是开方检验著名的“低频词缺陷”。因此开方检验也经常同其他因素如词频综合考虑来扬长避短。

信息增益:对于总数据的分类情况C, H(C) = -\sumplgp, 是总数据的信息的熵;条件熵,就是按某个特征将总数据划分为若干子集,H(C|X) = p1*H(C|x1)+p2*H(C|x2)+...; H(C|x1)就是特征X等于x1的数据的信息熵;H(C)-H(C|X)就是信息增益,越大表示特征X对于该数据集按照C的分类越好;(跟决策树的信息增益,一样一样的);对于文本分类里的特征选择,可以用某词w的出现or不出现表示特征X; 

 

文本分类:

1. 最简单的方法(KNN更简单?): 中心向量法;把训练数据按类进行向量加和,每一类得到一个中心向量;测试数据来了直接和所有中心向量计算cosine相似度;

2.朴素贝叶斯的多项式法和伯努利法

二者的计算粒度不一样,多项式模型以单词为粒度,伯努利模型以文档为粒度,因此二者的先验概率和类条件概率的计算方法都不同。

计算后验概率时,对于一个文档d,多项式模型中,只有在d中出现过的单词,才会参与后验概率计算;伯努利模型中,没有在d中出现,但是在全局单词表中出现的单词,也会参与计算,不过是作为“反方”参与的。

 

拼音提示:可以根据搜索日志,把用户经常输入的查询词赋予更高的权重;每个查询词得到拼音和拼音缩写,建立Trie树;(或者再转成带容错的自动机);用户输入拼音的时候遍历这个Trie树即可;

中文同义词近义词:同义词词林;HowNet;  Synonyms

机器翻译的历史:语法树翻译(似乎不是主流):输入英文句子,建立依存语法树,把该英文树转成中文树,按序遍历中文语法树,并把英文单词替换为中文字词;基于短语的翻译(神经网络之前,是主流)

 

情感识别:

给出褒义词贬义词词典,如何确定其中每个词的褒贬程度:对于这份词典里的每个字,统计其在褒义词里出现过的词频p, 在贬义词里出现过的词频n, 再考虑所有字在褒义词里出现的词频All_p,所有字在贬义词里出现的词频All_n, 后两者是为了应对褒义词贬义词数目不均衡的情况;褒义程度=[p/All_p] / [p/All_p+n/All_n], 贬义程度=[n/All_n] / [p/All_p+n/All_n];该字的整体褒贬倾向=褒义程度-贬义程度;一个词的褒贬倾向=该词所有字的褒贬倾向之和/该词的字数;(新来了一个词,也可以用这个方法估计它的褒贬倾向)

5类词:1.直接有褒贬倾向的词,常见的是名词、形容词、副词、动词。比如“精彩”,“荒诞”;2.表示程度的词,例如“很”、“非常”; 3.否定词,例如“不”、“没有”;4.表示转折的词,例如“但是”、“却”;5.合成词(词组),单个词没有什么褒贬义,合在一起有褒贬义,比如“载入史册”,“载入”和“史册”都没有褒贬义,合在一起就有褒义;

情感识别流程:

1. 对这段话进行分词,词性标注,类别标注(以上5种类别),极性标注(褒义,贬义,中性),程度标注(1~5)

2.匹配模板:比如:很(副词,2类词,中性,程度2) 精彩(形容词,1类词,褒义,程度2);<副词,2类词>-><形容词,1类词>就是一个模板,"很精彩"匹配上了;

3.所有模板词组组成一个序列;

4.第一遍扫描序列:找到<2类词,1类词>这样的对儿,把2类词的程度值乘到1类词的程度值上;

5.第二遍扫描序列:找3类词(否定词),将其后面第1个1类词的程度值取反;

6.第三遍扫描序列:以4类词(转折词)为基准将整个序列划分为多个小序列,每个小序列的1类词程度值加和到一起;把每个小序列的转折词的权值,乘到该小序列的加和上面;例如“虽然“的小序列要乘以0.5(减弱),“但是”的小序列要乘以1.7(加强)

 

DocId压缩:

整数的变长压缩(VInt):每个字节的首位是0表示没有下一个字节了,是1表示下一个字节还是这个数;(有些类似UTF-8编码);缺点:解压缩的时候执行的if太多,打断CPU预取流水线;

PForDelta压缩算法:90%的数据用b个bit表示;剩余10%的数据用32bit表示;原来顺序还保持,遇到长数据就用skip-step表示(即该数后面有几个短数);所有长数据从后往前排列;解压速度快(搜索引擎关心的是解压速度)

差分编码:X1,X2,X3,...==>X1,X2-X1,X3-X2,...; 结合变长压缩一起使用;

索引词压缩:

前缀压缩法:因为索引词都是按字典序排序的,所以前缀相同的可能性很大,所以后一个词表示为和前一个词的差异:<仙童前缀的字符长度,不同的字符长度,不同的字符>;例如term,termagancy,termagant, 压缩表示为:<0,4,term>,<4,6,agancy>,<8,1,t>

VInt,String的介绍以及4种常用规则

String的开头是一个VInt的长度; 用1位表示后面有没有Freq(默认Freq=1就没有); 跳跃表;

 

倒排索引的细节,全在这篇文章里。4大文件:

1. 词典索引:全部加载至内存;跳跃表;每个term都有指向词典文件对应term的offset(差分编码)

2. 词典:term的字符串用了前缀压缩法;每个term有指向文件3和文件4对应term的offset(2个都是差分编码)

3. 文档ID及在其中的出现词频:每个Term,有一个Array<DocID, Freq?>, 其中DocID用了差分编码,Freq用了1-bit跟随,还有一个跳表(可以好几层),跳表的每个节点包含以下信息:文档号(差分编码),payload的长度(1-bit跟随),文档号对应的倒排表中的节点在文件3中的偏移量(差分编码),文档号对应的倒排表中的节点在文件4中的偏移量(差分编码)。

4. 词的位置和权重:很规整,每个term对应一个doc数组,每个doc数组对应一个position数组,每个position包含<该词在该文档中的该次出现偏移量(差分编码), payload长度(1-bit跟随), payload数据>; 使用文件3的跳跃表来快速定位本文件里的信息;

2个次要文件:

1. 标准化因子文件:预先计算好term在不同doc和不同field中的权重,存好;一共field数*doc数个浮点数(本segment里的doc数)(每个浮点数只用1byte);权重值和<该doc的权重,该field的权重,该doc的该field的长度>三项有关;

2.删除文档文件:如果删的多,就用密集的bit数组格式;如果删的少,就用<byteId,byte内容>来存储稀疏bit数组;

 

正排索引的细节

fdt和fdx是核心;fdt里面存放了每个doc的所有field的内容;新版本里用了LZ4压缩

每到达一批删除操作,会生成一个新的.del文件;记录着删了哪些doc;

段的metadata是segment_N文件;field的metadata是.fnm文件;

 

正排索引Term Vector:

记录了每个doc的所有term及其出现位置;

可以用来做文档相似度匹配(MoreLikeThis);用的就是cosine距离;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值