ES高级搜索功能

1、多字段检索

1.1 多字段检索(multi_match)是啥?

概念:多字段检索,是组合查询的另一种形态,考试的时候如果考察多字段检索,并不一定必须使用multi_match,使用bool query,只要结果正确亦可,除非题目中明确要求(目前没有强制要求过)

语法:

复制代码
GET <index>/_search
{
  "query": {
    "multi_match": {
      "query": "<query keyword>",
      "type": "<multi_match_type>",
      "fields": [
        "<field_a>",
        "<field_b>"
      ]
    }
  }
}

1.2 multi_match和_source区别

  • multi_match:从哪些字段中检索,指的是查询条件

  • _source:查询的结果包含哪些字段,指的是元数据

打个形象的比喻,在MySQL中,Select * From Table Where a=x and b = x,那么multi_match即指的是a和b两个字段,而_source指的是*

1.3 best_fields:

1.3.1 概念:

侧重于"字段"维度,单个字段的得分权重大,对于同一个query,单个field匹配更多的term,则优先排序。

1.3.2 用法:

注意,best_fields是multi_match中type的默认值

复制代码
GET product/_search
{
  "query": {
    "multi_match" : {
      "query":      "super charge",
      "type":       "best_fields", // 默认
      "fields":     [ "name^2", "desc" ],
      "tie_breaker": 0.3
    }
  }
}

1.3.3 案例

针对于以下查询,包含两个查询条件:分别是条件1和条件2

复制代码
GET product/_search
{
  "query": {
    "dis_max": {
      "queries": [
        { "match": { "name": "chiji shouji" }},   #条件1
        { "match": { "desc": "chiji shouji" }}      #条件2
      ]
    }
  }
}

假设上述查询的执行得到以下结果,best_fields策略强调hits中单个字段的评分权重。打个比方:每一条hit代表一个奥运会的参加国,每个字段代表该国家的参赛运动员,但是限定每个国家只能派出一名运动员,其成绩就代表该国家的成绩,最后以该运动员的成绩代表国家进行排名。所谓"best_fields"就是说最好的字段嘛,用最好的字段的评分代表当前文档的最终评分,即侧重字段权重。在这个例子中,多个查询条件并未起到关键性作用。

1.3.4 tie_breaker参数

在best_fields策略中给其他剩余字段设置的权重值,取值范围 [0,1],其中 0 代表使用 dis_max 最佳匹配语句的普通逻辑,1表示所有匹配语句同等重要。最佳的精确值需要根据数据与查询调试得出,但是合理值应该与零接近(处于 0.1 - 0.4 之间),这样就不会颠覆 dis_max (Disjunction Max Query)最佳匹配性质的根本。

在上面例子中,如果一个国家仅仅由一个运动员的成绩来决定,显然不是很有代表性,因为一个国家可能整体实力很弱,但是有一个运动员(假设叫做阿尔法)就是特别的出类拔萃,世界第一!但是其他人都很弱,这时他就不能代表整个国家的实力了。反而可能另一个国家,虽然国内成绩最好的运动员没有"阿尔法"的成绩好,但是这个国家包揽了世界的第二名到第十名,并且实力比较接近,那这样这个国家的整体实力仍然是可以排第一的。所以我们不应该让第一名完全代表一个国家的成绩,一个更好的做法是:每个国家的最终成绩由所有运动员的成绩经过计算得来,每个运动员的成绩都可能影响总成绩,但是这个国家排名第一的运动员的成绩占的权重最大。这种做法更容易凸显一个国家的整体实力,这个整体实力就等价于我们搜索结果排名中的相关度。

用法:

复制代码
GET product/_search
{
  "query": {
    "dis_max": {
      "queries": [
        { "match": { "name": "super charge" }},
        { "match": { "desc": "super charge" }}
      ],
      "tie_breaker": 0.3 # 代表次要评分字段的权重是 0.3
    }
  }
}

1.3.5 类比

以下两个查询等价

查询1

复制代码
GET product/_search
{
  "query": {
    "dis_max": {
      "queries": [
        {
          "match": {
            "name": {
              "query": "chiji shouji",
              "boost": 2    # name字段评分两倍权重
            }
          }
        },
        {
          "match": {
            "desc": "chiji shouji"
          }
        }
      ],
      "tie_breaker": 0.3
    }
  }
}

查询2

复制代码
GET product/_search
{
  "query": {
    "multi_match" : {
      "query":      "super charge",
      "type":       "best_fields", // 默认
      "fields":     [ "name^2", "desc" ], # name字段评分两倍权重
      "tie_breaker": 0.3
    }
  }
}

1.4 most_fields:

1.4.1 概念

侧重于"查询"维度,单个查询条件的得分权重大,如果一次请求中,对于同一个doc,匹配到某个term的field越多,则越优先排序。

1.4.2 类比

以下两个查询脚本等价

查询1:

复制代码
# 下面查询中包含两个查询条件
GET product/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "name": "chiji shouji"
          }
        },
        {
          "match": {
            "desc": "chiji shouji"
          }
        }
      ]
    }
  }
}

查询2

复制代码
GET product/_search
{
  "query": {
    "multi_match": {
      "query": "chiji shouji",
      "type": "most_fields",
      "fields": [
        "name",
        "desc"
      ]
    }
  }
}

1.5 cross_fields:

注意: 理解"cross_fields"的概念之前,需要对ES的评分规则有基本的了解,戳:评分,学习ES评分的基本原理

1.5.1 概念

将任何与任一查询匹配的文档作为结果返回,但只将最佳匹配的评分作为查询的评分结果返回

1.5.2 用法

以下查询语义:

  • 吴 必须包含在 name.姓 或者 name.名 里

  • 磊 必须包含在 name.姓 或者 name.名 里

复制代码
GET teacher/_search
{
  "query": {
    "multi_match" : {
      "query":      "吴磊",
      "type":       "cross_fields",
      "fields":     [ "name.姓", "name.名" ],
      "operator":   "or"
    }
  }
}

1.5.3 案例

假设我们有如下"teacher"索引,索引中包含了"name"字段,包含"姓"和"名"两个field(案例中使用中文为方便观察和理解,切勿在生产环境中使用中文命名,一定要遵循命名规范)。

复制代码
POST /teacher/_bulk
{ "index": { "_id": "1"} }
{ "name" : {"姓" : "吴", "名" : "磊"} }
{ "index": { "_id": "2"} }	
{ "name" : {"姓" : "连", "名" : "鹏鹏"} }
{ "index": { "_id": "3"} }
{ "name" : { "姓" : "张","名" : "明明"} }
{ "index": { "_id": "4"} }
{ "name" : { "姓" : "周","名" : "志志"} }
{ "index": { "_id": "5"} }
{ "name" : {"姓" : "吴", "名" : "亦凡"} }
{ "index": { "_id": "6"} }
{ "name" : {"姓" : "吴", "名" : "京"} }
{ "index": { "_id": "7"} }
{ "name" : {"姓" : "吴", "名" : "彦祖"} }
{ "index": { "_id": "8"} }
{ "name" : {"姓" : "帅", "名" : "吴"} }
{ "index": { "_id": "9"} }
{ "name" : {"姓" : "连", "名" : "磊"} }
{ "index": { "_id": "10"} }
{ "name" : {"姓" : "周", "名" : "磊"} }
{ "index": { "_id": "11"} }
{ "name" : {"姓" : "张", "名" : "磊"} }
{ "index": { "_id": "12"} }
{ "name" : {"姓" : "马", "名" : "磊"} }
#{ "index": { "_id": "13"} }
#{ "name" : {"姓" : "诸葛", "名" : "吴磊"} }

我们执行以上代码创建teacher索引,并且执行以下查询语句

复制代码
# 语义: 默认分词器的对“吴磊”的分词结果为“吴”和“磊”
# name.姓 中包含 “吴” 或者 “磊”  
# OR  
# name.名 中包含 “吴” 或者 “磊” 
# 如果设置了"operator": "and",则中间 OR 的关系变为 AND
GET teacher/_search
{
  "query": {
    "multi_match": {
      "query": "吴 磊",
      "type": "most_fields",
      "fields": [
        "name.姓",
        "name.名"
      ]
      // ,"operator": "and"
    }
  }
}

根据上面查询的语义,我们期望的结果是:姓为"吴"并且名为"磊"的doc评分最高,然而结果却如下:

复制代码
{
  "took" : 3,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 9,
      "relation" : "eq"
    },
    "max_score" : 2.4548545,
    "hits" : [
      {
        "_index" : "teacher",
        "_type" : "_doc",
        "_id" : "8",
        "_score" : 2.4548545,
        "_source" : {
          "name" : {
            "姓" : "帅",
            "名" : "吴"
          }
        }
      },
      {
        "_index" : "teacher",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 2.03873,
        "_source" : {
          "name" : {
            "姓" : "吴",
            "名" : "磊"
          }
        }
      },
      {
        "_index" : "teacher",
        "_type" : "_doc",
        "_id" : "5",
        "_score" : 1.060872,
        "_source" : {
          "name" : {
            "姓" : "吴",
            "名" : "亦凡"
          }
        }
      },
      {
        "_index" : "teacher",
        "_type" : "_doc",
        "_id" : "6",
        "_score" : 1.060872,
        "_source" : {
          "name" : {
            "姓" : "吴",
            "名" : "京"
          }
        }
      },
      {
        "_index" : "teacher",
        "_type" : "_doc",
        "_id" : "7",
        "_score" : 1.060872,
        "_source" : {
          "name" : {
            "姓" : "吴",
            "名" : "彦祖"
          }
        }
      },
      {
        "_index" : "teacher",
        "_type" : "_doc",
        "_id" : "9",
        "_score" : 0.977858,
        "_source" : {
          "name" : {
            "姓" : "连",
            "名" : "磊"
          }
        }
      },
      {
        "_index" : "teacher",
        "_type" : "_doc",
        "_id" : "10",
        "_score" : 0.977858,
        "_source" : {
          "name" : {
            "姓" : "周",
            "名" : "磊"
          }
        }
      },
      {
        "_index" : "teacher",
        "_type" : "_doc",
        "_id" : "11",
        "_score" : 0.977858,
        "_source" : {
          "name" : {
            "姓" : "张",
            "名" : "磊"
          }
        }
      },
      {
        "_index" : "teacher",
        "_type" : "_doc",
        "_id" : "12",
        "_score" : 0.977858,
        "_source" : {
          "name" : {
            "姓" : "马",
            "名" : "磊"
          }
        }
      }
    ]
  }
}

上面结果显示,名叫"帅磊"的doc排在了最前面,即便我们使用best_fields策略结果也是"帅磊"评分最高,因为导致这个结果的原因和使用哪种搜索策略并无关系。这些然不是我们希望的结果。那么导致上述问题的原因是什么呢?看以下三条基本的评分规则:

评分基本规则:

  • 词频(TF term frequency ):关键词在每个doc中出现的次数,词频越高,评分越高

  • 反词频( IDF inverse doc frequency):关键词在整个索引中出现的次数,反词频越高,评分越低

  • 每个doc的长度,越长相关度评分越低

分析结果:

在上述案例中,"吴磊"作为预期结果,其中"吴"字作为姓氏是非常常见的,"磊"作为名也是非常常见的。反应在索引中,他们的IDF都是非常高的,而反词频越高则评分越低,因此吴磊在索引中的IDF评分则会很低。

而"帅磊"中"帅"作为姓氏却是非常少见的,因此IDF的得分就很高。在词频相同的情况下就会导致以上不符合常理的搜索预期。

解决办法:

为了避免某一个字段的词频或者反词频对结果产生巨大影响,我们需要把"姓"和"名"作为一个整体来查询,体现在代码上即:

复制代码
# 吴 必须包含在 name.姓 或者 name.名 里
# 并且
# 磊 必须包含在 name.姓 或者 name.名 里
GET teacher/_search
{
  "query": {
    "multi_match" : {
      "query":      "吴磊",
      "type":       "cross_fields",
      "fields":     [ "name.姓", "name.名" ],
      "operator":   "and"
    }
  }
}

2、搜索模板

3、Term Vector

3.1 场景及作用

3.2 基本用法

3.2.1 Term Vector选项

映射选项 解释
no 不存储术语向量。(默认)
yes 只存储字段中的术语。
with_positions 存储条款和位置。
with_offsets 存储术语和字符偏移。
with_positions_offsets 术语、位置和字符偏移被存储。
with_positions_payloads 存储术语、位置和有效载荷。
with_positions_offsets_payloads 存储术语、位置、偏移量和有效载荷。

3.2.2 查询参数

  • fields(可选,字符串)要包含在统计信息中的字段的逗号分隔列表或通配符表达式。

除非在completion_fieldsfielddata_fields参数中提供了特定字段列表,否则用作默认列表。

  • field_statistics (可选,布尔值)如果true,则响应包括文档计数、文档频率总和和总词频总和。默认为true.

  • <offsets> (可选,布尔值)如果true,则响应包括术语偏移量。默认为true.

  • payloads (可选,布尔值)如果true,则响应包括术语有效负载。默认为true.

  • positions (可选,布尔值)如果true,则响应包括术语位置。默认为true.

  • preference(可选,字符串)指定应在其上执行操作的节点或分片。默认随机。

  • routing(可选,字符串)用于将操作路由到特定分片的自定义值。

  • realtime (可选,布尔值)如果true,则请求是实时的,而不是接近实时的。默认为true. 请参阅实时

  • term_statistics (可选,布尔值)如果true,则响应包括词频和文档频率。默认为false.

  • version (可选,布尔值)如果true,则返回文档版本作为命中的一部分。

  • version_type (可选,枚举)特定版本类型:external, external_gte.

4、高亮查询

4.1 多字段高亮

4.2 三种高亮显示器(荧光笔)

4.2.1 unified highlighter

4.2.2 Plain highlighter

4.2.3 Fast vector highlighter

4.3 高亮的作用域

5、地理位置搜索

5.1 使用场景

5.2 两种数据类型

5.2.1 geo_point:

概念:经纬度坐标,只支持WGS84坐标系,坐标范围Lat值为[-90,90],Lon为[-180,180]

  • latitude:维度 缩写:lat

  • longitude:经度 缩写:lon

  • ignore_malformed:则忽略格式错误的地理位置。如果false(默认)

五种存储方式

5.2.2 geo_shape

概念:ES的特殊类型之一,用来描述复杂的几何图形的类型,比如点、线、面,多边形等二维几何模型。

  • GeoJSON:GeoJSON是一种用于编码各种地理数据结构的格式,支持以下几种几何类型:

    • Point:点

    • LineString:线段

    • Polygon:多边形

    • MultiPoint:多点

    • MultiLineString:多线段

    • MultiPolygon:多边形集合

    • Feature:具有其他属性的对象

  • WKT(Well-Known Text):POINT(125.6 10.1)

GeoJSON(OGC)和WKT到Elasticsearch类型的映射关系

GeoJSON类型 WKT类型 Elasticsearch类型 描述
Point POINT point 单个地理坐标。注意:Elasticsearch仅使用WGS-84坐标。
LineString LINESTRING linestring 给定两个或两个以上点的任意线。
Polygon POLYGON polygon 一个封闭的多边形,其第一个点和最后一个点必须匹配,因此需要n + 1顶点创建一个带n边的多边形和一个最小的4顶点。
MultiPoint MULTIPOINT multipoint 一组未连接但可能相关的点。
MultiLineString MULTILINESTRING multilinestring 单独的线串数组。
MultiPolygon MULTIPOLYGON multipolygon 一组单独的多边形。
GeometryCollection GEOMETRYCOLLECTION geometrycollection 与JSON形状相似的GeoJSON形状, multi*但可以同时存在多种类型(例如,Point和LineString)。
N/A BBOX envelope 通过仅指定左上和右下点指定的边界矩形。
N/A N/A circle 由中心点和半径指定的圆,单位为,默认为METERS。

5.3 Geo_point Based Request

5.3.1 矩形查询(geo_bounding box)

概念:在同一个平面内,两个点确定一个矩形,搜索矩形内的坐标。

  • top_left:矩形左上点坐标

  • bottom_right:矩形右上角表

5.3.2 半径查询(geo_distance)

概念:以某个点为圆心查找指定半径的圆内的坐标。

  • distance:距离单位,默认是米,支持以下选项

    • Mile(英里):mi 或者 miles

    • Yard(码):yd 或者 yards

    • Feet(英尺):ft 或者 feet

    • Inch(英寸):in 或者 inch

    • Kilometer(公里):km 或者 kilometers

    • Meter(米):m 或者 meters

    • Centimeter(厘米):cm 或者 centimeters

    • Millimeter(毫米): mm 或者 millimeters

    • Nautical mile(海里): NM , nmi , 或者 nauticalmiles

  • distance_type:计算距离的方式

    • arc(默认值):更准确,但是速度慢

    • plane:(更快,但在长距离和极点附近不准确)

5.3.3 多边形(geo_polygon)

概念:查找给定多个点连成的多边形内的坐标。

5.4 Geo_shape Based Request

概念:支持指定几何图形相交、包含或是不相交等图形检索

5.4.1 地理几何分类(geo_shape type)

  • 点(point)

  • 矩形(envelope)

  • 多边形 (polygon)

  • 圆形(circle)

5.4.2 地理几何存储

注:圆形处理精度解释

表示圆的多边形的精度定义为error_distance。这种差异越小,多边形越接近理想圆。下表是旨在帮助捕获在给定不同输入的情况下圆的半径如何影响多边形的边数的表格。最小边数为4,最大为1000。

error_distance 半径(米) 多边形的边数
1 1 4
1 10 14
1 100 45
1 1,000 141
1 10,000 445
1 100,000 1000

5.4.3 地理几何检索

  • Inline Shape Definition:内联形状

  • Pre-Indexed Shape:预定义形状

    • id- 包含预索引形状的文档ID。

    • index- 索引的名称,其中预索引形状为:默认形状。

    • routing- 非必须。

    • path- 包含预索引形状的指定路径,默认形状。

  • Spatial Relations:空间关系

    • INTERSECTS- (default) Return all documents whose shape field intersects the query geometry。

    • DISJOINT - Return all documents whose shape field has nothing in common with the query geometry

    • WITHIN - Return all documents whose shape field is within the query geometry。

    • CONTAINS- Return all documents whose shape field contains the query geometry。

相关推荐
codinglf5 小时前
大模型质检盒子实测:7天破解制造质检困局
大数据·运维·人工智能
Bechamz5 小时前
大数据开发学习Day24
大数据·学习
北京自在科技5 小时前
Find Hub App 小更新
android·ios·安卓·findmy·airtag
lbb 小魔仙5 小时前
2026远程办公软件夏季深度横测:ToDesk、向日葵、网易UU远程全面对比,远控白皮书
android·服务器·网络协议·tcp/ip·postgresql
NOCSAH5 小时前
统好AI:用AI技术为传统ERP系统注入新活力
大数据·人工智能
coding_fei5 小时前
AudioServer初始化过程
android
智慧化智能化数字化方案5 小时前
智能制造——解读IBM装备制造业大数据驱动的企业架构优化与智能化转型规划方案【附全文阅读】
大数据·架构·制造·装备制造业全寿命周期质量管理·装备制造业智能工厂·装备制造集团scm·sap大型装备制造集团erp
hsD5mSMu55 小时前
从零开始学Flink:Flink SQL 极简入门
大数据·sql·flink
brucelee1866 小时前
Docker 运行 Android 模拟器
android·docker·容器