elasticsearch 高级搜索示例 es7.0

摘要:
不指定fields搜索POSTmytest/_search{"explain":true,"query":{"match":{"content":"好评"}}}搜索结果为3条。
1 基础数据

1.1 创建索引

PUT mytest
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "text",
            "analyzer": "standard"
          }
        }
      },
      "tag": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      },
      "content": {
        "type": "text",
        "fields": {
          "std": {
            "type": "text",
            "analyzer": "standard"
          },
          "cn": {
            "type": "text",
            "analyzer": "ik_smart"
          }
        }
      },
      "score": {
        "type": "byte"
      },
      "time":{
        "type": "date"
      }
    }
  },
  "settings": {
    "index": {
      "number_of_shards": "1",
      "number_of_replicas": "0"
    }
  }
}

1.2 写入数据

POST mytest/_doc/001
{
  "title": "好评不错",
  "tag": "精彩",
  "content": "这里必须有一些内容,来表示这个评论是好评",
  "score": 90,
  "time": 1596441469000
}
POST mytest/_doc/002
{
  "title": "一般评价",
  "tag": "普通",
  "content": "这里可以有一些内容,来表示这个评论是一般的",
  "score": 80,
  "time": 1596355069000
}
POST mytest/_doc/003
{
  "title": "很差的评价",
  "tag": "TCL",
  "content": "这里没有一些内容,来表示这个评论是OK的",
  "score": 20,
  "time": 1596268669000
}
POST mytest/_doc/004
{
  "title": "超级好评",
  "tag": "精彩",
  "content": "这里必须有一些内容,来表示这个评论是好评好评好评好评好评好评好评好评好评好评好评好评好评",
  "score": 2,
  "time": 1596441469000
}
2 短语匹配

2.1 不指定匹配的 fields 时候, 是否会查找全部字段?

不指定 fields 搜索

POST mytest/_search
{
  "explain": true,
  "query": {
    "match": {
      "content": "好评"
    }
  }
}

搜索结果为 3 条。在 explain 的结果中可以看到, details 评分统计了两个字段的结果

为了验证上面结果, 在指定域搜索只能看到一条结果

POST mytest/_search
{
  "query": {
    "match": {
      "content.cn": "好评"
    }
  }
}

2.2 match 和 match_phrase 区别

POST mytest/_search
{
  "explain": false,
  "query": {
    "match": {
      "content.cn":{
        "query": "这里可以有一些内容",
        "analyzer": "ik_smart"
      }
    }
  }
}

"这里可以有一些内容" 通过 ik_smart 分词器被分成了 [这里 可以 有 一些 内容]
五个词都放入到 es 中搜索, 所以这里可以搜索出三个结果
可以通过比例限制匹配的结果, 限制到 90% 后, 只能匹配到 1 条结果

POST mytest/_search
{
  "query": {
    "match": {
      "content.cn":{
        "query": "这里可以有一些内容",
        "analyzer": "ik_smart",
        "minimum_should_match": "90%"
      }
    }
  }
}

match_phrase 只能匹配到 1 条结果, 如果把文本换成 "这里可以有内容一些", 就不能匹配到内容了
这时需要使用 slop 完成近似匹配, 允许有顺序的差异. 同时, 使用 match 匹配的时候, 词的顺序不影响结果得分

POST mytest/_search
{
  "query": {
    "match_phrase": {
      "content.cn":{
        "query": "这里可以有一些内容",
        "analyzer": "ik_smart",
        "slop": 0
      }
    }
  }
}

2.3 精确搜索的时候, 可以使用默认分词器, 以达到精确的目的

在搜索中输入 "以有一些内容" 不完整的内容, 也可以搜索到精确的结果
修改为 match 可以

POST mytest/_search
{
  "query": {
    "match_phrase": {
      "content.std":{
        "query": "以有一些内容",
        "analyzer": "standard"
      }
    }
  }
}
3 自定义打分

3.1 打分公式

score(q,d) = queryNorm(q)            //归一化因子
             ·coord(q,d)             //协调因子
             ·∑( tf(t in d)          //词频
                ·idf(t)²             //逆向文档频率
                ·t.getBoost()        //权重
                ·norm(t,d)           //字段长度归一值
              )(t in q)

queryNorm 查询归化因子: 会被应用到每个文档, 不能被更改, 总而言之, 可以被忽略
coord 协调因子: 可以为那些查询词包含度高的文档提供奖励, 文档里出现的查询词越多, 它越有机会成为好的匹配结果
协调因子将评分与文档里匹配词的数量相乘,然后除以查询里所有词的数量,如果使用协调因子,评分会变成:
文档里有 fox → 评分: 1.5 * 1 / 3 = 0.5
文档里有 quick fox → 评分: 3.0 * 2 / 3 = 2.0
文档里有 quick brown fox → 评分: 4.5 * 3 / 3 = 4.5
协调因子能使包含所有三个词的文档比只包含两个词的文档评分要高出很多

3.2 提升查询权重

POST mytest/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "title": {"query": "好评", "boost": 10}
          }
        },
        {"match": {"content": "有一些内容"}
        }
      ]
    }
  }
}

3.3 结合 function_score 查询 与 field_value_factor 查询可以实现按照文档的字段来影响文档评分

POST mytest/_search
{
  "query": {
    "function_score": {
      "query": {
        "multi_match": {"query": "好评","fields": ["title", "content"]}
      },
      "functions": [
        {"field_value_factor": {"field": "score"}}
      ]
    }
  }
}

new_score = old_score * number_of_votes
这样会导致 votes 为 0 的文档评分为 0,而且 votes 值过大会掩盖掉全文评分

3.4 一般会使用 modifier 参数来平滑 votes 的值

POST mytest/_search
{
  "query": {
    "function_score": {
      "query": {
        "multi_match": {"query": "好评","fields": ["title", "content"]}
      },
      "functions": [
        {"field_value_factor": {"field": "score", "modifier": "log1p"}}
      ]
    }
  }
}

应用值为 log1p 的 modifier 后的评分计算公式:
new_score = old_score * log(1 + number_of_votes)

modifier 的可以为: none ,log ,log1p ,log2p ,ln ,ln1p ,ln2p ,square ,sqrt ,reciprocal

3.5 factor 可以通过将 votes 字段与 factor 的积来调节受欢迎程度效果的高低

"functions": [
        {"field_value_factor": {"field": "score", "modifier": "ln1p", "factor": 10}}
      ]

添加了 factor 会使公式变成这样:
new_score = old_score * log(1 + factor * number_of_votes)

3.6 通过参数 boost_mode 来控制函数与查询评分 _score 合并后的结果,参数接受的值

multiply: 评分 _score 与函数值的积(默认)
sum: 评分 _score 与函数值的和
min: 评分 _score 与函数值间的较小值
max: 评分 _score 与函数值间的较大值
replace: 函数值替代评分 _score

"functions":[],
"boost_mode": "sum"

之前请求的公式现在变成下面这样:
new_score = old_score + log(1 + 0.1 * number_of_votes)

3.7 可以使用 max_boost 参数限制一个函数的最大效果

"boost_mode": "sum"
"max_boost": 1.5

无论 field_value_factor 函数的结果如何,最终结果都不会大于 1.5 。
注意 max_boost 只对函数的结果进行限制,不会对最终评分 _score 产生直接影响。

3.8 评分模式 score_mode

每个函数返回一个结果,所以需要一种将多个结果缩减到单个值的方式,然后才能将其与原始评分 _score 合并。
评分模式 score_mode 参数正好扮演这样的角色, 它接受以下值:

multiply : 函数结果求积(默认)。
sum : 函数结果求和。
avg : 函数结果的平均值。
max : 函数结果的最大值。
min : 函数结果的最小值。
first : 使用首个函数(可以有过滤器,也可能没有)的结果作为最终结果
在本例中,我们将每个过滤器匹配结果的权重 weight 求和,并将其作为最终评分结果,所以会使用 sum 评分模式。
不与任何过滤器匹配的文档会保有其原始评分, _score 值的为 1 。

3.9 衰减函数

这需要使用 function_score 查询提供的一组 衰减函数(decay functions)
linear 线性函数
exp 指数函数
gauss 高斯函数

所有三个函数都接受如下参数:
origin:中心点 或字段可能的最佳值,落在原点 origin 上的文档评分 _score 为满分 1.0 。
scale:衰减率,即一个文档从原点 origin 下落时,评分 _score 改变的速度。(例如,每 £10 欧元或每 100 米)。
decay:从原点 origin 衰减到 scale 所得的评分 _score ,默认值为 0.5 。
offset:以原点 origin 为中心点,为其设置一个非零的偏移量 offset 覆盖一个范围,而不只是单个原点。在范围 -offset <= origin <= +offset 内的所有评分 _score 都是 1.0

      "functions": [
        {
          "exp": {
            "time": {
              "origin": "1596530751000",
              "scale": "10d",
              "offset": "5d",
              "decay": 0.5
            }
          }
        }
      ]

免责声明:文章转载自《elasticsearch 高级搜索示例 es7.0》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇SQLServer聚集索引导致的插入性能低ElasticSearch 问题分析:No data nodes with HTTP-enabled available下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

nodejs body-parser 解析post数据

安装 $ npm install body-parser API var bodyPaeser =require('body-parser') 可以通过body-parser 对象创建中间件,当接收到客户端请求时所有的中间件都会给req.body 添加属性,请求体为空,则解析为空{} (或者出现错误)。 bodyParser.json(options) 中...

通过SSE(Server-Send Event)实现服务器主动向浏览器端推送消息

一、SSE介绍 1.EventSource 对象 SSE 的客户端 API 部署在EventSource对象上。下面的代码可以检测浏览器是否支持 SSE。 if (‘EventSource’ in window) {  }  使用 SSE 时,浏览器首先生成一个EventSource实例,向服务器发起连接。 var source = new EventSo...

xios封装

封装的意义 1.提高代码可读性2.提高代码可维护性3.减少代码书写 封装 import axios from 'axios' axios.defaults.baseURL = 'http://127.0.0.1:8000' // 全局设置网络超时 axios.defaults.timeout = 10000; //设置请求头信息 axios.defau...

使用CURL与ElasticSearch服务进行通信

其他高级的语言统一使用RESTful API和JSON,Java开发者可使用Java API。 Java API 如果你正在使用 Java,在代码中你可以使用 Elasticsearch 内置的两个客户端: 节点客户端(Node client) 节点客户端作为一个非数据节点加入到本地集群中。换句话说,它本身不保存任何数据,但是它知道数据在集群中的哪...

springboot ElasticSearch 简单的全文检索高亮

原文:https://segmentfault.com/a/1190000017324038?utm_source=tag-newest 首先引入依赖 <dependency> <groupId>org.springframework.boot</groupId> &l...

jmeter随笔(2)--post接口参数化问题

今天试着做了一下post接口测试,并对其输入的参数进行参数化设置,在这里总结一下测试的过程中遇到的问题,以及解决方式: 一、使用body data设置参数: 1,首先,使用Fiddler录制post请求,并发送成功,导成jmx格式,并用jmeter打开; 2,此时,不设置参数,运行,OK,运行成功,其传递的值为以下格式: {"tagid":"aaaaa",...