ElasticSearch的Mapping和DSL语言

ElasticSearch的Mapping和DSL语言

mapping(映射)

  • 定义索引中的字段名称
  • 定义字段的数据类型,例如字符串,数字,布尔等。
  • 字段,倒排索引的相关配置(Analyzer)

es中的Mapping分为动态映射和静态映射。

动态映射

在文档写入索引中时,会根据字段自动识别类型,这种机制成为动态映射。

类型自动识别

ES 的动态映射会尝试自动推断字段的类型,比如:

  • 字符串 类型字段:默认情况下,ES 会将字符串字段映射为 text 类型,并且创建一个 keyword 子字段以支持精确匹配。
  • 数值 类型字段:会自动映射为 integer, long, float, double 等类型。
  • 布尔值 类型字段:会映射为 boolean 类型。
  • 日期 类型字段:会映射为 date 类型。
  • 对象嵌套 类型字段:会自动映射为 objectnested 类型。
静态映射

静态映射时在index创建时可以事先定义好映射,包含文档的各字段的类型,分词器等。这种方式成为静态映射。类似于关系型数据库中创建表结构的形式。

关于后期更改mapping字段类型?
  • 新增加字段

    • ​ dynamic设置为true时,一单有新增字段的文档写入,mapping也同时更新

    • ​ dynamic设置为false时,mapping不会被更新,新增字段的数据无法被索引,但是信息会出现在_source中

    • ​ dynamic设置为strict,文档写入失败,抛出异常

  • 已有字段是不支持映射更新的

    • 如果修改了字段类型,会导致已被索引的数据无法搜索。

    • lucene实现的倒排索引,一旦生成后,就不支持修改

    • 如果希望改变字段类型,可以利用reindex api,重建索引。

重建索引步骤
  1. 创建一个和原索引类似的索引,需要更改的mapping同步创建
  2. 利用reindex命令重建索引
  3. 保证兼容性,把原有的索引干掉,再创建新索引的别名为原索引的名称 PUT /destIndex/_alias/sourceIndex
POST _reindex
{
	"source" : {
		"index" : "user"
	},
	"dest" : {
		"index" : "user2"
	}
}
常用mapping参数配置
  • type: 定义字段类型

    1. 数值类型 (Numeric Types)
    • integer: 32-bit 整数,范围从 -2,147,483,648 到 2,147,483,647。
    • long: 64-bit 整数,范围从 -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807。
    • short: 16-bit 整数,范围从 -32,768 到 32,767。
    • byte: 8-bit 整数,范围从 -128 到 127。
    • float: 单精度浮点数,通常用于表示小数或科学记数法中的数据,精度为 32 位。
    • double: 双精度浮点数,通常用于高精度计算,精度为 64 位。
    • scaled_float: 用于存储浮点数,但以整数形式存储,并通过一个缩放因子来恢复浮点值。适用于对高精度浮点数有严格要求的场景。
    1. 字符串类型 (Text Types)
    • text: 用于存储全文本数据,通常用于需要分词和全文搜索的字段。Elasticsearch 会对 text 字段进行分词,并建立反向索引。
    • keyword: 用于存储精确匹配的数据,不会被分词。适合用于过滤、排序、聚合等操作。常用于存储标签、类别、ID 等精确值。
    1. 日期类型 (Date Type)
    • date: 用于存储日期和时间数据。支持多种日期格式,可以使用 yyyy-MM-ddepoch_millis 等格式。
    1. 布尔类型 (Boolean Type)
    • boolean: 用于存储布尔值(truefalse)。
    1. 对象类型 (Object Type)
    • object: 用于存储嵌套的 JSON 对象,可以包含其他字段和子对象。每个字段都会被索引,适合存储结构化的数据。
    • nested: 类似于 object,但允许在查询时处理嵌套文档中的子对象。这在需要对嵌套对象进行复杂查询时非常有用。
    1. 地理空间类型 (Geo Types)
    • geo_point: 用于存储地理坐标(经度和纬度)。支持地理位置相关的查询,如范围查询和距离计算。
    • geo_shape: 用于存储复杂的地理形状(如多边形、圆形、线段等)。适合需要精确地理计算和空间查询的场景。
    1. 二进制类型 (Binary Type)
    • binary: 用于存储二进制数据,如文件或图像的内容。数据以 Base64 编码形式存储。
    1. 其他类型 (Special Types)
    • ip: 用于存储 IP 地址,支持 IPv4 和 IPv6 地址的存储和查询。
    • alias: 用于创建别名,可以将别名指向一个或多个索引,使得可以通过别名来进行索引操作。
  • index: 默认为true,如果设置成false,则该字段不可搜索。

  • analyzer:定义分词器类型,如ik_smart,ik_max_word

  • null_value: 指定为空值的替代值,如null_value = “null”,可通过查询null查询空值

  • copy_to:将字段赋值到规定的一个字段中。如省市县分字段,另外定义一个address字段,可以使用copy_to赋值到address字段中

index_template 和mapping_template

可以通过预定义索引模板和映射模板,通用的配置

Query DSL

restApi + JSON构建查询请求体的一种查询语句。

数据初始化

创建hotel数据,对应的mapping如下

PUT hotel
{
  "mappings": {
    "properties" : {
        "address" : {
          "type" : "text",
          "analyzer": "ik_max_word", 
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "brand" : {
          "type" : "keyword"
        },
        "business" : {
          "type" : "text",
          "analyzer": "ik_max_word", 
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "city" : {
          "type" : "keyword"
        },
        "id" : {
          "type" : "long"
        },
        "location" : {
          "type" : "text",
          "analyzer": "ik_max_word", 
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "name" : {
          "type" : "text",
          "analyzer": "ik_max_word", 
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "pic" : {
          "type" : "keyword",
          "index": false
        },
        "price" : {
          "type" : "long"
        },
        "score" : {
          "type" : "long"
        }
      }
    }
}
无条件查询,默认返回十条数据

SELECT * FROM HOTEL LIMIT 10 OFFSET 0;

POST hotel/_search
{
  "query": {
    "match_all": {}
  }
}
分页查询
from和size关键字
POST hotel/_search
{
  "query": {
    "match_all": {}
  },
  "from": 0,
  "size": 10
}
页码限制
Result window is too large, from + size must be less than or equal to: [10000]

es限制from + size 不能大于10000,否则会抛异常。

可通过修改单个索引的index.max_reuslt_window值将该限制更改。

PUT /INDEXNAME/_setttings
{
	"index.max_result_window" : "20000"
}

名称为注意index.的形式

修改索引的索引限制,但后面新增的索引限制还是为10000,后续新增的索引不受该更改影响

PUT /_all/_settings
{
	"index.max_result_window" : "20000"
}

es不推荐使用from,size的方式进行深度分页

深分页查询Scroll

scroll API 适用于需要大量数据的提取任务,例如批量处理或数据迁移。它提供了一种机制,通过创建一个持续的上下文来逐步检索大量数据。

使用 scroll API 的基本步骤:

1.初始化滚动上下文:会返回一个scroll_id给第二步使用

GET /my_index/_search/scroll
{
  "scroll": "1m",  // 设置滚动上下文的生存时间
  "size": 1000,    // 每次检索的文档数量
  "query": {
    "match_all": {}
  }
}

2. 继续获取数据:使用 _scroll_id 继续获取数据。

GET /_search/scroll
{
  "scroll": "1m",
  "scroll_id": "DnF1ZXJ5VGhlbkZldGNoZTM1N...."
}

3. 清除滚动上下文(当不再需要时):

DELETE /_search/scroll
{
  "scroll_id": ["DnF1ZXJ5VGhlbkZldGNoZTM1N...."]
}

深分页问题

深分页查询由于是使用快照保存查询出的结果,所以在这段时间的数据准确性不能保证。

排序查询
POST hotel/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "price": {
        "order": "asc"
      }
    },
    {
      "score": {
        "order": "desc"
      }
    }
  ]
}

利用sort排序查询,支持多个字段排序,有先后顺序,如根据价格升序后,如果价格相同,则根据score倒序。

过滤返回字段

通过_source属性筛选返回的字段

POST hotel/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "price": {
        "order": "asc"
      }
    },
    {
      "score": {
        "order": "desc"
      }
    }
  ],
  "_source": ["name","address","price","score","brand"]
}
条件查询(重点)
分词匹配(match)

match匹配时会对所查找的关键词进行分词,然后按分词匹配查询

match支持以下参数

  • query: 指定匹配的值
  • operator: 匹配条件的类型
    • and 所有条件都要匹配
    • or 匹配一个即可
    • minmum should match: 最低匹配度,即条件在倒排索引中的最低匹配度,匹配分词的最少数量
POST hotel/_search
{
  "query": {
    "match": {
      "address": {
        "query": "宝安广场",
        "operator": "or"
      }
    }
  }
}

默认的operator为or,则上述条件可通过宝安广场两个词语去地址查询。只要满足一个词语都可以被查询出来

operator为and,则address必须满足宝安和广场两个词语才能被查询出来,需要精确结果的时候需要更换成and

注意match下的query不要跟最开始的query混淆

POST hotel/_search
{
  "query": {
    "match": {
      "address": {
        "query": "宝安广场",
        "minimum_should_match": 2
      }
    }
  }
}

minimum_should_match 定义了必须至少匹配到个词语才能满足。

短语匹配(match_phrase)

match_phrase的分词结果必须在被检索的字段的分词中都包含,而且顺序必须相同,默认顺序必须都是连续,所以叫短语匹配,如匹配创业二路步行街

就是在一段话中截取一小段话来匹配。

注意,如查询词汇为创业二路,查看IK分词器结果

{
  "tokens" : [
    {
      "token" : "创业",
      "start_offset" : 0,
      "end_offset" : 2,
      "type" : "CN_WORD",
      "position" : 0
    },
    {
      "token" : "二路",
      "start_offset" : 2,
      "end_offset" : 4,
      "type" : "CN_WORD",
      "position" : 1
    },
    {
      "token" : "二",
      "start_offset" : 2,
      "end_offset" : 3,
      "type" : "TYPE_CNUM",
      "position" : 2
    },
    {
      "token" : "路",
      "start_offset" : 3,
      "end_offset" : 4,
      "type" : "COUNT",
      "position" : 3
    }
  ]
}

此时,创业二路为连续的分词,而创业二为不连续的分词。所以在短语查询的时候

POST hotel/_search
{
  "query": {
    "match_phrase": {
      "address": "创业二路"
    }
  }
}

此时能查询出结果

POST hotel/_search
{
  "query": {
    "match_phrase": {
      "address": "创业二"
    }
  }
}

查询创业二的时候不能查出结果来。

slop属性

slop属性告诉match_phrase查询词条能够相隔多远时仍然将文档视为匹配。类似于跳过分词中的position

POST hotel/_search
{
  "query": {
    "match_phrase": {
      "address": {
        "query": "创业二",
        "slop" : 1
      }
    }
  }
}

此时能查询出结果

多字段查询(multi_match)

如在name和address中查询七天酒店

POST hotel/_search
{
  "query": {
    "multi_match": {
      "query": "7天酒店",
      "fields": ["name","address"],
      "operator": "and"
    }
  }
}

默认operator为or。

Query String

Query String 允许我们在查询字符串中指定AND,OR,NOT等条件,同时也和multi_match一样,可以指定多字段查询

AND,OR,NOT必须得大写

未指定字段查询,查询索引中所有的字段。
POST hotel/_search
{
  "query": {
    "query_string": {
      "query": "如家 OR 七天"
    }
  }
}
指定单个字段查询
POST hotel/_search
{
  "query": {
    "query_string": {
      "default_field": "brand", 
      "query": "速8  OR  7天"
    }
  }
}
指定多个字段查询
POST hotel/_search
{
  "query": {
    "query_string": {
      "fields": ["brand","name"], 
      "query": "速8  OR  7天"
    }
  }
}
Simple Query String

类似Query String ,但是会忽略错误的语法,同时只支持部分查询语法,不支持AND OR NOT,会当做字符串处理。支持部分逻辑:

  • +替代AND
  • | 替代 OR
  • -替代NOT

下面两张写法含义一样

POST hotel/_search
{
  "query": {
    "simple_query_string": {
      "query": "速8酒店",
      "fields": ["name","brand"],
      "default_operator": "and"
    }
  }
}


POST hotel/_search
{
  "query": {
    "simple_query_string": {
      "query": "速8 + 酒店",
      "fields": ["name","brand"]
    }
  }
}
关键词查询 (term)

Term用来使用关键词查询(精确匹配),还可以用来查询没有进行分词的数据类型(keyword,date,integer,long,double,boolean or ip)。

模糊匹配用match,精确匹配用term

term会直接将查询不分词进行精确匹配,但是查询的内容是可以分词的,一旦内容的某个分词和查询的内容匹配上。也可以查出来

这条可以查出来,因为地址有西城这个分词

POST hotel/_search
{
  "query": {
    "term": {
      "address": {
        "value": "西城"
      }
    }
  }
}

下面这条查询不到数据

POST hotel/_search
{
  "query": {
    "term": {
      "address": {
        "value": "西城北京市西城"
      }
    }
  }
}

term查询不分词字段没必要进行算分,因为算分会损耗性能

constant_score

constant_score可以不用算分直接返回

POST hotel/_search
{
  "query": {
    "constant_score": {
      "filter": {
        "term": {
          "address.keyword": "西城北京市西城区德胜门内大街兴华胡同五福里2号"
        }
      }
    }
  }
}
前缀查询(prefix)

它会对分词后的term进行前缀搜索。

  • 它不会分析要搜索字符串,传入的前缀就是想要查找的前缀
  • 默认状态下,前缀查询不做相关度查询计算,它只是将所有匹配的文档返回,然后赋予所有相关分数值为1。它的行为更像是一个过滤器而不是查询。两者的实际区别是过滤器可以被缓存,而前缀查询不行。

prefix的原理: 需要遍历所有倒排索引,并比较每个term是否以所指定的前缀开头。

这玩意儿会遍历所有倒排索引,所以严重损耗性能。

POST hotel/_search
{
  "query": {
    "prefix": {
      "address": {
        "value": "北京"
      }
    }
  }
}
通配符查询(wildcard)

类似于mysql中的like,不建议使用,有了倒排索引还需要这个干嘛?

POST hotel/_search
{
  "query": {
    "wildcard": {
      "name": {
        "value": "*上海*"
      }
    }
  }
}
范围查询(range)

查询价格在100到200之间的所有酒店

POST hotel/_search
{
  "query": {
    "range": {
      "price": {
        "gte": 100,
        "lte": 200
      }
    }
  },
  "sort": [
    {
      "price": {
        "order": "asc"
      }
    }
  ]
}
模糊查询(fuzzy)

在实际搜索中,如商品搜索,有时候用户输入的商品名称可能会有错别字,但是我们应该就算有错别字也能搜索到相应的产品信息,这个时候fuzzy功能就来了。

fuzzy查询的两个重要参数:

  • fuzziness: 表示输入的关键字通过几次操作可以转变成ES库里面的对应Filed字段

    • 操作是指,新增一个字符,删除一个字符,修改一个字符,每次操作可以记做编辑距离
      为1
    • 如中文集团到中威集团编辑距离就是1,只需要修改一个字符;
    • 该参数默认值为0,即不开启模糊查询
    • 如果fuzziness值在这里设置成2,会把编辑距离为2的东东集团也查出来
  • prefix length: 表示限制输入关键字和ES对应查询field的内容开头的第n个字符必须完全匹
    配,不允许错别字匹配

    • 如这里等于1,则表示开头的字必须匹配,不匹配则不返回
    • 默认值也是0
    • 加大prefix length的值可以提高效率和准确率

查询名称中包含如家的酒店,通过儒家查询,可以查询出如家的酒店信息

POST hotel/_search
{
  "query": {
    "fuzzy": {
      "name": {
        "value": "儒家",
        "fuzziness": 1
      }
    }
  }
}

另外一种写法,推荐使用

POST hotel/_search
{
  "query": {
    "match": {
      "name": {
        "query": "儒家" ,
        "fuzziness": 1
      }
    }
  }
}
高亮(highlight)

highlight 关键字: 可以让符合条件的文档中的关键词高亮

highlight相关属性

  • pre_tags 前缀标签
  • post_tags 后缀标签
  • tags_schema 设置为styled可以使用内置高亮样式
  • require_field_match 多字段高亮需要设置为false
POST hotel/_search
{
  "query": {
    "match": {
      "name": "如家"
    }
  },
  "highlight": {
    "fields": {
      "name" : {}
    }
  }
}

会多返回一个hignlight字段,只是多了个html标签

 "highlight" : {
          "name" : [
            "<em>如家</em>酒店(北京良乡西路店)"
          ]
}
自定义标签
POST hotel/_search
{
  "query": {
    "match": {
      "name": "如家"
    }
  },
  "highlight": {
    "fields": {
      "name" : {}
    },
    "pre_tags": ["<span style='color:red'>"],
    "post_tags": ["</span>"]
  }
}
"highlight" : {
          "name" : [
            "<span style='color:red'>如家</span>酒店(北京良乡西路店)"
          ]
        }
多字段高亮

如果查询的其他字段也需要对查询的内容进行高亮,则需要将 require_field_match 设置成false,默认为true

POST hotel/_search
{
  "query": {
    "match": {
      "name": "北京"
    }
  },
  "highlight": {
    "fields": {
      "name" : {},
      "address": {}
    },
    "pre_tags": ["<span style='color:red'>"],
    "post_tags": ["</span>"],
    "require_field_match": "false"
  }
}
"highlight" : {
          "address" : [
            "西城<span style='color:red'>北京</span>市西城区德胜门内大街兴华胡同五福里2号"
          ],
          "name" : [
            "速8酒店<span style='color:red'>北京</span>后海店"
          ]
        }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值