ES如何提高准确率之【term-centric】

这篇具有很好参考价值的文章主要介绍了ES如何提高准确率之【term-centric】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

提高准确率的方法有很多,但是要在提高准确率的同时保证召回率往往比较困难,本文只介绍一种比较常见的情况。

问题场景

我们经常搜索内容,往往不止针对某个字段进行搜索,比如:标题、内容,往往都是一起搜索的。
index结构如下:

{
  "settings": {
    "number_of_shards": "1",
    "number_of_replicas": "0"
  },
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "ik_smart"
      },
      "content": {
        "type": "text",
        "analyzer": "ik_smart"
      }
    }
  }
}

样例数据如下:

{"index":{"_id":1}}
{"title":"我喜欢的一种水果","content":"我喜欢的苹果是红色的,含有铜、碘、锰、锌、钾等元素"}
{"index":{"_id":2}}
{"title":"红色的番茄","content":"番茄是一种红色的水果,含有各种维生素以及糖分"}
{"index":{"_id":3}}
{"title":"樱桃的介绍","content":"樱桃是红色的,含有丰富的糖分、铁、维生素C、蛋白质、维生素E、维生素B族和胡萝卜素"}
{"index":{"_id":4}}
{"title":"不知名介绍","content":"我爱吃红色,红色,红色,红色,红色,红色,红色,红色,红色,红色,红色,红色,红色,红色,红色,红色的水果"}

现在我要搜索【红色的苹果】,我们人眼看下来,id=1的文档肯定是最佳匹配的。但我们真实搜索结果会怎么样呢?
搜索语句假设如下:

{
    "query": {
        "bool": {
            "should": [
                {
                    "match": {
                        "title": "红色的苹果"
                    }
                },
                {
                    "match": {
                        "content": "红色的苹果"
                    }
                }
            ]
        }
    }
}

上面搜索语句dsl语句看着略微复杂,我们换个写法,效果一样

{
    "query": {
        "multi_match": {
            "query": "红色的苹果",
            "type": "most_fields",
            "fields": [
                "title",
                "content"
            ]
        }
    }
}

结果:

[
    {
        "_index":"dong_analyzer_test2",
        "_type":"_doc",
        "_id":"2",
        "_score":1.9675379,
        "_source":{
            "title":"红色的番茄",
            "content":"番茄是一种红色的水果,含有各种维生素以及糖分"
        }
    },
    {
        "_index":"dong_analyzer_test2",
        "_type":"_doc",
        "_id":"1",
        "_score":1.9362588,
        "_source":{
            "title":"我喜欢的一种水果",
            "content":"我喜欢的苹果是红色的,含有铜、碘、锰、锌、钾等元素"
        }
    },
    {
        "_index":"dong_analyzer_test2",
        "_type":"_doc",
        "_id":"3",
        "_score":0.63812846,
        "_source":{
            "title":"樱桃的介绍",
            "content":"樱桃是红色的,含有丰富的糖分、铁、维生素C、蛋白质、维生素E、维生素B族和胡萝卜素"
        }
    },
    {
        "_index":"dong_analyzer_test2",
        "_type":"_doc",
        "_id":"4",
        "_score":0.2719918,
        "_source":{
            "title":"不知名介绍",
            "content":"我爱吃红色,红色,红色,红色,红色,红色,红色,红色,红色,红色,红色,红色,红色,红色,红色,红色的水果"
        }
    }
]

很明显和我们人眼评分肯定是不一样的

思考

问题1:为什么id=2的番茄评分最高?

我们先看下切词

{
    "tokens": [
        {
            "token": "红色",
            "start_offset": 0,
            "end_offset": 2,
            "type": "CN_WORD",
            "position": 0
        },
        {
            "token": "的",
            "start_offset": 2,
            "end_offset": 3,
            "type": "CN_CHAR",
            "position": 1
        },
        {
            "token": "苹果",
            "start_offset": 3,
            "end_offset": 5,
            "type": "CN_WORD",
            "position": 2
        }
    ]
}

因为番茄中title中有【红色】【的】,content中有【红色】【的】,title和content同时都命中了,所以匹配到了它。

问题2:id=1的content中不仅有【苹果】还有【红色】【的】为什么评分比id=2的番茄低?

因为id=1的title种没有【红色】【的】,尽管id=1的content的匹配度 大于 id=2的content,但是title匹配度不及id=2

问题3:凭什么title分低一点,content分高一点不能把整体评分拉齐?

一般来说title分低,只要content分高,照样总分可以超过其他文档。那这个样例的问题出在哪了呢?

我们再看下样例:

{"title":"我喜欢的一种水果","content":"我喜欢的苹果是红色的,含有铜、碘、锰、锌、钾等元素"}
{"title":"红色的番茄","content":"番茄是一种红色的水果,含有各种维生素以及糖分"}
{"title":"樱桃的介绍","content":"樱桃是红色的,含有丰富的糖分、铁、维生素C、蛋白质、维生素E、维生素B族和胡萝卜素"}
{"title":"不知名介绍","content":"我爱吃红色,红色,红色,红色,红色,红色,红色,红色,红色,红色,红色,红色,红色,红色,红色,红色的水果"}

我们发现content中【红色】这个词出现频率非常高。
我们可以想到es的搜索算法中有一个逆向文档频率,它描述的是某个词在所有文档中出现的频率越高,它的权重越低。
回到问题2,content分高一点不能把整体评分拉齐?答案是可以的,但是问题出在了content的分虽然高,但是高的不多,比起title差的远,上面样例中title出现【红色】只有一个而已。

解决方案

方案1 - 调整权重(不建议)

能不能给title权重降低一点?这样就能弥补【红色】权重低的问题了。

  • 针对这个样例来说,这样做是可以的。但这仅仅是个样例,现实中我们不能这样去解决问题,因为上面的样例完全可以逆转,让title和content字段互换。难道又要去调整content的权重么?

方案2 - 精确匹配(略微不建议)

上面有个问题就是,id=2的文档中,根本没有【苹果】也被匹配出来了,那么我精确匹配是不是就可以了

{
    "query": {
        "multi_match": {
            "query": "红色的苹果",
            "type": "most_fields",
            "operator": "and",
            "fields": [
                "title",
                "content"
            ]
        }
    }
}
  • and代表所有词都必须匹配,当然也可以使用minimum_should_match,但本文的样例必须使用100%

查询结果:

[
    {
        "_index":"dong_analyzer_test2",
        "_type":"_doc",
        "_id":"1",
        "_score":1.499949,
        "_source":{
            "title":"我喜欢的一种水果",
            "content":"我喜欢的苹果是红色的,含有铜、碘、锰、锌、钾等元素"
        }
    }
]

确实我们最希望匹配出来的结果被匹配出来了,并且排在了第一,但是其他不是很相关的文档却没有匹配出来,这降低了召回率。所以这种方案不是特别推荐
备注:这种解决问题的思路是没有问题的,往往这种精确匹配要搭配其他查询条件一起使用,但和本文想讨论的问题不相关,放到其他文章中去介绍。

方案3 - 新建字段(还行)

上面的问题关键在哪呢?
仔细分析可以发现,我们的需求是希望搜索一个query进行多个字段(title、content)的搜索。换句话说,我们其实是希望title和content是一个字段(他们共享TF/IDF),我们并不希望因为某些词在content中出现很频繁,但在title中出现不频繁导致最终评分不符合预期。

根据上面思路,我们是不是可以建一个新字段,把title和content拼接在一起就行了?

{
    "settings":{
        "number_of_shards":"1",
        "number_of_replicas":"0"
    },
    "mappings":{
        "properties":{
            "title":{
                "type":"text",
                "analyzer":"ik_smart"
            },
            "content":{
                "type":"text",
                "analyzer":"ik_smart"
            },
            "title_content":{
                "type":"text",
                "analyzer":"ik_smart"
            }
        }
    }
}

这样做是可以的,但是有两个弊端

  1. 业务系统在插入的时候,需要手动把title和content拼接在一起,然后整体写入title_content。
  2. es存储空间变大,title和content的内容相当于存了双份

方案4 - 新建字段索引(不错)

怎么解决方案3的这个问题呢?
可以利用copy_to

{
    "settings":{
        "number_of_shards":"1",
        "number_of_replicas":"0"
    },
    "mappings":{
        "person":{
            "properties":{
                "title":{
                    "type":"text",
                    "analyzer":"ik_smart",
                    "copy_to":"title_content"
                },
                "content":{
                    "type":"text",
                    "analyzer":"ik_smart",
                    "copy_to":"title_content"
                },
                "title_content":{
                    "type":"string",
                    "analyzer":"ik_smart"
                }
            }
        }
    }
}

这样es帮我们在插入数据的时候自动把映射的索引copy到了title_content中去。
注意:这里所有的分词器要保持一致
但它同样还有弊端:

  1. 在创建索引的时候就必须考虑到这种情况,不然还要刷重刷数据

方案5 - term-centric(推荐)

其实解决办法除了重新刷一遍数据以外,还有别的更加优雅的方式,可以不用在建索引的时候把所有情况考虑到位。
利用cross_fields词中心式的方式来解决

{
    "query": {
        "multi_match": {
            "query": "红色的苹果",
            "type": "cross_fields",
            "fields": [
                "title",
                "content"
            ]
        }
    }
}

搜索结果:

[
    {
        "_index":"dong_analyzer_test2",
        "_type":"_doc",
        "_id":"1",
        "_score":1.499949,
        "_source":{
            "title":"我喜欢的一种水果",
            "content":"我喜欢的苹果是红色的,含有铜、碘、锰、锌、钾等元素"
        }
    },
    {
        "_index":"dong_analyzer_test2",
        "_type":"_doc",
        "_id":"4",
        "_score":0.30932084,
        "_source":{
            "title":"不知名介绍",
            "content":"我爱吃红色,红色,红色,红色,红色,红色,红色,红色,红色,红色,红色,红色,红色,红色,红色,红色的水果"
        }
    },
    {
        "_index":"dong_analyzer_test2",
        "_type":"_doc",
        "_id":"2",
        "_score":0.2428131,
        "_source":{
            "title":"红色的番茄",
            "content":"番茄是一种红色的水果,含有各种维生素以及糖分"
        }
    },
    {
        "_index":"dong_analyzer_test2",
        "_type":"_doc",
        "_id":"3",
        "_score":0.23682731,
        "_source":{
            "title":"樱桃的介绍",
            "content":"樱桃是红色的,含有丰富的糖分、铁、维生素C、蛋白质、维生素E、维生素B族和胡萝卜素"
        }
    }
]

他的原理就是把所有字段当成一个大字段,并在每个字段中查找每个词。
看下es的对cross_fields的分析过程

blended(terms:[title:红色, content:红色]) 
blended(terms:[title:, content:]) 
blended(terms:[title:苹果, content:苹果])

可以发现es进行三次大搜索,每次大搜索下面有两次小搜索,每次大搜索都是把切词的结果词进行匹配,每次小搜索都是把当前的切词对title和content进行terms匹配,最后把里层和外层搜索评分相加,得到最终结果。

总结

本文探讨了多字段搜索的时候,每个字段的词频和逆向文档频率不同带来的搜索准确率问题。
问题的根本原因在于:搜索的时候大多数都是针对字段进行搜索,但本文中的情况是希望对词进行搜索。
解决思路也是很简单,就是把多个字段的词频和逆向文档频率整合到一起,当然可以在建立索引的时候整合,也可以搜索的时候进行整合查询。文章来源地址https://www.toymoban.com/news/detail-782406.html

到了这里,关于ES如何提高准确率之【term-centric】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 深度学习提高模型准确率方法

    我们已经收集好了一个数据集,建立了一个神经网络,并训练了模型,在测试和验证阶段最后得到的准确率不高不到90%。或者没有达到业务的期望(需要100%)。 下面列举一些提高模型性能指标的策略或技巧,来提高模型的准确率。 使用更多数据 最简单的方法就是增加数据集

    2024年02月03日
    浏览(55)
  • Python批量识别图片文字(数字识别模式)大幅度提高数字识别准确率

    目录   一、使用beautiful soup库爬取网页图片 二、使用pytesseract库识别图片中数据,并将数据存入txt文件 三、用pandas库实现txt文件到csv文件的转换   一、使用beautiful soup库爬取网页图片  该网站中有需要的数据,但是是以图片形式存在。 这样就给我们爬取数据造成了一些困扰

    2024年02月13日
    浏览(43)
  • 环境监测中的人工智能:提高数据质量与预测准确率的关键

    环境监测是现代社会中的一个重要领域,它涉及到对大气、水体、土壤、生物等环境因素的监测和分析,以支持政策制定、资源管理、环境保护等多方面的需求。随着大数据技术的发展,环境监测数据的规模和复杂性不断增加,这为环境监测提供了更多的信息和洞察力。然而

    2024年02月21日
    浏览(60)
  • 定位时长缩减90%:酷家乐如何提升系统故障根因分析准确率?

    酷家乐开发魔方语言的目的是解决其2B SaaS系统在复杂微服务架构下的故障定位难题,以提升系统稳定性并加速故障恢复。由于原监控工具操作复杂,需要人工逐项点击且依赖经验,导致处理效率低下。魔方语言通过自动化根因分析,显著提升了故障处理的覆盖率和准确率,从

    2024年03月28日
    浏览(61)
  • 语义分割准确率计算

    目录 pytorch版 pytorch准确率,miou: sklearn版

    2024年02月06日
    浏览(57)
  • 在分类任务中准确率(accuracy)、精确率(precision)、召回率(recall)和 F1 分数是常用的性能指标,如何在python中使用呢?

    在机器学习和数据科学中,准确率(accuracy)、精确率(precision)、召回率(recall)和 F1 分数是常用的性能指标,用于评估分类模型的性能。 准确率是模型预测正确的样本数占总样本数的比例。 精确率是指在预测为正的样本中,实际为正的比例。它关注的是预测为正的样本

    2024年01月19日
    浏览(59)
  • 自然语言处理学习笔记(八)———— 准确率

    目录 1.准确率定义 2.混淆矩阵与TP/FN/FP/TN 3. 精确率 4.召回率 5.F1值 6.中文分词的P、R、F1计算 7.实现 1.准确率定义         准确率是用来衡量一个系统的准确程度的值,可以理解为一系列评测指标。当预测与答案的数量相等时,准确率指的是系统做出正确判断的次数除以总

    2024年02月09日
    浏览(44)
  • 识别准确率竟如此高,实时语音识别服务

    本文将介绍一个准确率非常高的语音识别框架,那就是FunASR,这个框架的模型训练数据超过几万个小时,经过测试,准确率非常高。本文将介绍如何启动WebSocket服务和Android调用这个服务来实时识别,一边说话一边出结果。 安装Pytorch。 使用conda安装ffmpeg等一些库。 安装其他依

    2024年02月07日
    浏览(43)
  • 深度学习准确率提升之天花板分析

    OCR文字识别流水线主要分为三个模块:文字检测-字符分割-字符识别 训练完成后整个系统的准确率是72%,需要进一步提升准确率就需要单独分析每个模块的提升空间。 1)对于文件检测模块,把训练集的图像人工确保标注准确的文本位置来作为输入,系统准确率提升到89% 2)对

    2024年02月12日
    浏览(55)
  • Resnet18训练CIFAR10 准确率95%

    准确率 95.31% 几个关键点: 1、改模型:原始的resnet18首层使用的7x7的卷积核,CIFAR10图片太小不适合,要改成3x3的,步长和padding都要一并改成1。因为图太小,最大池化层也同样没用,删掉。最后一个全连接层输出改成10。 2、图片增强不要太多,只要训练集和验证集结果没有出

    2024年02月02日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包