希望长大对我而言,是可以做更多想做的事,而不是被迫做更多不想做的事...... 首页 ElasticSearch之TF/IDF 丁D 学无止境 2019-09-26 09:20 79537已阅读 ElasticSearch 相关度分数 TF/IDF 摘要本文将了解一下ElasticSearch控制相关度分数的TF/IDF,和向量空间模型 ```js 当我们使用es进行全文搜索的时候,es使用TF/IDF算法来计算scroe。 Term Frequency/Inverse Document Frequency简写(TF/IDF):词频/逆向文档频率 TF:词频,词条在当前文档中出现的有多频繁?越频繁的话,那么权重就越高。出现2次的 分数肯定比1次高。 IDF:逆向文档频率,词条在集合所有文档里出现的频率是多少?频次越高,权重 越低。 注意:这里的所有文档是指本地分片 假设我们现在有两个document doc1:hello, today is very good doc2:hi world, how are you 我们搜索hello world TF: term frequency 找到hello在doc1中出现了几次,1次,会根据出现的次数给个分数 一个term在一个doc中,出现的次数越多,那么最后给的相关度评分就会越高 IDF:inversed document frequency 找到hello在所有的doc中出现的次数,1次 一个term在所有的doc中,出现的次数越多,那么最后给的相关度评分就会越低 length norm hello搜索的那个field的长度,field长度越长,给的相关度评分越低; field长度越短,给的相关度评分越高 最后,会将hello这个term,对doc1的分数,综合TF,IDF,length norm,计算出来一个综合性的分数 hello world --> doc1 --> hello对doc1的分数,world对doc1的分数 --> 但是最后hello world query要对doc1有一个总的分数 --> vector space model ``` >**注意:** >IDF:词条在集合所有文档里出现的频率是多少,这里的所有文档是指本地分片的所有文档,不是所有分片的所有文档,所以当index有多个share计算出来的记过就会不准确。 **方案:** **测试环境**:可以通过设置只有一个share来处理问题,或者搜索请求中添加?**search_type=dfs_query_then_fetch**。dfs表示分布频度搜索(Distributed Frequency Search),它会告诉ES首先从每个分片中获取本地IDF,然后计算整个索引上的全局IDF。 **生产环境**:我们的文档被均匀地分布了,多个个分片上计算得到的IDF应该是相同的。现在想象一下如果含有foo的5份文档被保存在了分片1上,而只有1份含有foo的文档被保存在了分片2上。在这种情况下,词条foo在分片1上就是一个非常常见的词条(重要性很低),但是在分片2上,它是非常少见的词条(重要性很高)。因此,这些IDF的差异就会导致错误的结果。 实际情况下,这并不是一个问题。当你向索引中添加的文档越多,本地IDF和全局IDF之间的差异就会逐渐减小。考虑到真实的世界中的数据量,本地IDF很快就会变的正常。问题不是相关度,而是数据量太小了。 不要在生产环境中使用dfs_query_then_fetch。它真的是不必要的。性能太低。 ```js TF:词频 如果不在意词在某个字段中出现的频次,而只在意是否出现过,则可以在字段映射中禁用词频统计: PUT /my_index { "mappings": { "doc": { "properties": { "text": { "type": "string", "index_options": "docs" } } } } } 将参数 index_options 设置为 docs 可以禁用词频统计及词频位置,这个映射的字段不会计算词的出现次数,对于短语或近似查询也不可用。要求精确查询的 not_analyzed 字符串字段会默认使用该设置。 ``` ```js length norm:字段长度的归一值 字段长度的归一值对全文搜索非常重要, 许多其他字段不需要有归一值。无论文档是否 包括这个字段,索引中每个文档的每个 string 字段都大约占用 1 个 byte 的空 间。对于 not_analyzed 字符串字段的归一值默认是禁用的,而对于 analyzed 字 段也可以通过修改字段映射禁用归一值: PUT /my_index { "mappings": { "doc": { "properties": { "text": { "type": "string", "norms": { "enabled": false } } } } } } 这个字段不会将字段长度归一值考虑在内,长字段和短字段会以相同长度计算评分。 对于有些应用场景如日志,归一值不是很有用,要关心的只是字段是否包含特殊的错误码 或者特定的浏览器唯一标识符。字段的长度对结果没有影响,禁用归一值可以节省大量内 存空间。 ``` **向量空间模型** ```js 向量空间模型提供了一种多词条查询的比较方法。它的输出是一个代表了文档和查询之间匹配程度的分值。为了计算该分值,文档和查询都被表示成向量。 一个向量实际上就是一个包含了数值的一维数组,比如: [1,2,5,22,3,8] 在向量空间模型中,向量中的每个数值都是由TF/IDF计算得到的一个词条的权重。 假设我们查询了"happy hippopotamus"。一个像happy这样的常见单词的权重是较 低的,然而像hippopotamus这样的罕见单词则拥有较高的权重。假设happy的权重为 2而hippopotamus的权重为5。我们可以使用坐标来表达这个简单的二维向量 - [2, 5] 一条从坐标(0, 0)到坐标(2, 5)的直线,如下所示: ``` ![alt](/upload/elas_17in01.png ) ```js 现在,假设我们有三份文档: I am happy in summer. After Christmas I’m a hippopotamus. The happy hippopotamus helped Harry. 我们可以为每份文档创建一个类似的向量,它由每个查询词条的权重组成 - 也就是出现在文档中的词条happy和hippopotamus,然后将它绘制在坐标中,如下图: 文档1:(happy,____________) — [2,0] 文档2:( ___ ,hippopotamus) — [0,5] 文档3:(happy,hippopotamus) — [2,5] 向量的一个很棒的性质是它们能够被比较。通过测量查询向量和文档向量间的角度,我们可以给每份文档计算一个相关度分值。文档1和查询之间的角度较大,因此它的相关度较低。文档2和查询更靠近,所以它的相关度更高,而文档3和查询之间则是一个完美的匹配。 ``` ![alt](/upload/elas_17in02.png ) >在实际中,只有二维向量(两个词的查询)可以在平面上表示,幸运的是, 线性代数 ——作为数学中处理向量的一个分支——为我们提供了计算两个多维向量间角度工具,这意味着可以使用如上同样的方式来解释多个词的查询。 **参考** https://www.elastic.co/guide/cn/elasticsearch/guide/current/scoring-theory.html#tfidf https://blog.csdn.net/wuzhiwei549/article/details/80407607 https://www.iteye.com/blog/study121007-2294453 很赞哦! (0) 上一篇:Elasticsearch6.3.2之x-pack 下一篇:Elasticsearch搜索特性 目录 点击排行 Elasticsearch6.3.2之x-pack redis哨兵 2019-07-09 22:05 Redis+Twemproxy+HAProxy+Keepalived 2019-07-12 17:20 GC优化策略和相关实践案例 2019-10-10 10:54 JVM垃圾回收器 2019-10-10 10:23 标签云 Java Spring MVC Mybatis Ansible Elasticsearch Redis Hive Docker Kubernetes RocketMQ Jenkins Nginx 友情链接 郑晓博客 佛布朗斯基 凉风有信 MarkHoo's Blog 冰洛博客 南实博客 Rui | 丁D Java研发工程师 生活可以用「没办法」三个字概括。但别人的没办法是「腿长,没办法」、「长得好看,没办法」、「有才华,没办法」。而你的没办法,是真的没办法。 请作者喝咖啡