导入测试数据

https://gitee.com/UnityAlvin/test/blob/master/accounts.json

导入测试数据。

  1. POST bank/account/_bulk

Elasticsearch 进阶检索 - 图1

SearchAPI

以下操作都是在Kibana dev-tools执行

uri+检索参数

请求

通过REST request uri 发送搜索参数

  1. GET bank/_search?q=*&sort=account_number:asc
  • bank/:bank这个索引下
  • _search:固定格式
  • ?:所有的检索条件
  • q=*:查询所有
  • &sort=account_number:asc:按照account_number升序排列

结果

Elasticsearch 默认会返回10条数据

Elasticsearch 进阶检索 - 图2

  • took – Elasticsearch 执行搜索的时间(毫秒)
  • timed_out – 搜索是否超时
  • _shards – 多少个分片被搜索了,以及统计了成功/失败的搜索分片
  • hits.total - 查询到的记录
  • hits.total.value - 表示有多少条记录被匹配到了
  • hits.total.relation - 检索的关系
  • hits.max_score – 最大得分(全文检索用)
  • hits.hits- 实际的搜索结果数组(默认为前 10 的文档)
  • hits.hits._score - 相关性得分(全文检索用)
  • hits.hits.sort - 结果的排序 key(键)(没有则按 score 排序)

uri+请求体

通过REST request body 来发送它们

请求

  1. GET bank/_search
  2. {
  3. "query": {
  4. "match_all": {}
  5. },
  6. "sort": [
  7. {
  8. "account_number": "desc"
  9. }
  10. ]
  11. }
  • "query":查询条件
  • "match_all":匹配所有的详细规则
  • "sort":排序条件,可以添加多个
  • "account_number": "desc":按照account_number降序排列

结果

Elasticsearch 进阶检索 - 图3

Query DSL

Elasticsearch提供了一个可以执行查询的Json风格的DSL(domain-specific language 领域特定语言)。被称为Query DSL,该查询语言非常全面。

基本语法格式

一个查询语句的典型结构:

  1. QUERY_NAME:{
  2. ARGUMENT:VALUE,
  3. ARGUMENT:VALUE,...
  4. }

如果针对于某个字段,那么它的结构如下:

  1. {
  2. QUERY_NAME:{
  3. FIELD_NAME:{
  4. ARGUMENT:VALUE,
  5. ARGUMENT:VALUE,...
  6. }
  7. }
  8. }

请求示例:

  1. GET bank/_search
  2. {
  3. "query": {
  4. "match_all": {}
  5. },
  6. "from": 0,
  7. "size": 5,
  8. "sort": [
  9. {
  10. "account_number": {
  11. "order": "desc"
  12. },
  13. "balance": {
  14. "order": "asc"
  15. }
  16. }
  17. ]
  18. }
  19. # match_all 查询类型【代表查询所有的所有】,es中可以在query中组合非常多的查询类型完成复杂查询;
  20. # from+size 限定,完成分页功能;从第几条数据开始,每页有多少数据
  21. # sort 排序,多字段排序,会在前序字段相等时后续字段内部排序,否则以前序为准;

返回部分字段

请求

  1. GET bank/_search
  2. {
  3. "query": {
  4. "match_all": {}
  5. },
  6. "from": 0,
  7. "size": 5,
  8. "sort": [
  9. {
  10. "account_number": {
  11. "order": "desc"
  12. }
  13. }
  14. ],
  15. "_source": ["balance","firstname"]
  16. }
  • "_source":查询部分字段
  • "from":从第1条记录开始
  • "size":查询5条记录

结果

Elasticsearch 进阶检索 - 图4

match-匹配查询

精确匹配-基本类型(非字符串)

查找 account_number 为 20 的数据 ,建议使用 term 进行检索

  1. GET bank/_search
  2. {
  3. "query": {
  4. "match": {
  5. "account_number": 20
  6. }
  7. }
  8. }

精确匹配-字符串

查找 address 为 288 Mill Street 的数据

  1. GET bank/_search
  2. {
  3. "query": {
  4. "match": {
  5. "address.keyword": "288 Mill Street"
  6. }
  7. }
  8. }

全文检索-字符串

全文检索,会对检索条件进行分词匹配,最终会按照得分降序排列。

查找 address 包含 mill 或 lane 的数据

  1. GET bank/_search
  2. {
  3. "query": {
  4. "match": {
  5. "address": "mill lane"
  6. }
  7. }
  8. }

全文检索-基本类型(非字符串)

  1. GET bank/_search
  2. {
  3. "query": {
  4. "match": {
  5. "account_number": "20"
  6. }
  7. }
  8. }

match_phrase-短语匹配

将需要匹配的值当成一个整体(不分词)进行检索

查找 address 包含 mill lane 的数据

  1. GET bank/_search
  2. {
  3. "query": {
  4. "match_phrase": {
  5. "address": "mill lane"
  6. }
  7. }
  8. }

multi_math-多字段匹配

查找 city 或 address 包含 mill movico 的数据,会对查询条件分词

  1. GET bank/_search
  2. {
  3. "query": {
  4. "multi_match": {
  5. "query": "mill movico",
  6. "fields": [
  7. "city",
  8. "address"
  9. ]
  10. }
  11. }
  12. }

bool-复合查询

复合语句可以合并任何其他查询语句,包括复合语句。这就意味着,复合语句之间可以互相嵌套,可以表达非常复杂的逻辑。

查询 address 包含 mill 、 gender 包含 M 、age 不是 18 、lastname 最好包含 Wallace 的数据

  1. GET bank/_search
  2. {
  3. "query": {
  4. "bool": {
  5. "must": [
  6. {
  7. "match": {
  8. "address": "mill"
  9. }
  10. },
  11. {
  12. "match": {
  13. "gender": "M"
  14. }
  15. }
  16. ],
  17. "must_not": [
  18. {
  19. "match": {
  20. "age": 18
  21. }
  22. }
  23. ],
  24. "should": [
  25. {
  26. "match": {
  27. "lastname": "Wallace"
  28. }
  29. }
  30. ]
  31. }
  32. }
  33. }
  • "must":必须满足的条件
  • "must_not":必须不满足的条件
  • "should":非必须满足的条件,满足之后可加分

filter-结果过滤

查询 18 <= age <= 30 的数据

  1. GET bank/_search
  2. {
  3. "query": {
  4. "bool": {
  5. "filter": {
  6. "range": {
  7. "age": {
  8. "gte": 18,
  9. "lte": 30
  10. }
  11. }
  12. }
  13. }
  14. }
  15. }

filter 对结果进行过滤,且不计算相关性得分。

term-精确检索

Elasticsearch 官方对于非文本字段,推荐使用 term 来精确检索。

查找 age 为 28 的数据

  1. GET bank/_search
  2. {
  3. "query": {
  4. "term": {
  5. "age": "28"
  6. }
  7. }
  8. }

Aggregation-执行聚合

聚合提供了从数据中分组和提取数据的能力。最简单的聚合方法大致等于 SQL GROUPBY 和 SQL 聚合函数。在 Elasticsearch 中,您有执行搜索返回 hits(命中结果),并且同时返回聚合结果,把一个响应中的所有 hits(命中结果)分隔开的能力。这是非常强大且有效的,您可以执行查询和多个聚合,并且在一次使用中得到各自的(任何一个的)返回结果,使用一次简洁和简化的 API 来避免网络往返。

语法

  1. "aggs/aggregations" : {
  2. "<聚合名称>" : {
  3. "<聚合类型>" : {
  4. <聚合体的内容>
  5. }
  6. [,"meta" : { [<meta_data_body>] } ]?
  7. [,"aggs/aggregations" : { [<sub_aggregation>]+ } ]?
  8. }
  9. [,"<聚合2>" : { ... } ]*
  10. }

一个aggs中可以有多个同级聚合,如果想在一个聚合里面添加子聚合的话,需要为子聚合单独加个aggs才可以

示例1

  1. # 搜索 address 中包含 mill 的所有人的年龄分布、平均年龄、平均薪资
  2. GET bank/_search
  3. {
  4. "query": {
  5. "match": {
  6. "address": "mill"
  7. }
  8. },
  9. "aggs": {
  10. "ageAgg": {
  11. "terms": {
  12. "field": "age",
  13. "size": 10
  14. }
  15. },
  16. "ageAvg":{
  17. "avg": {
  18. "field": "age"
  19. }
  20. },
  21. "balanceAvg":{
  22. "avg": {
  23. "field": "balance"
  24. }
  25. }
  26. },
  27. "size": 0
  28. }

示例2

  1. # 按照年龄聚合,并且求这些年龄段的人的平均薪资
  2. GET bank/_search
  3. {
  4. "query": {
  5. "match_all": {}
  6. },
  7. "aggs": {
  8. "ageAggs": {
  9. "terms": {
  10. "field": "age",
  11. "size": 100
  12. },
  13. "aggs": {
  14. "balanceAvg": {
  15. "avg": {
  16. "field": "balance"
  17. }
  18. }
  19. }
  20. }
  21. },
  22. "size": 0
  23. }

示例3

  1. # 查出所有年龄分布,并查出这些年龄段中M的平均薪资、F的平均薪资、以及这个年龄段的平均薪资
  2. GET bank/_search
  3. {
  4. "query": {
  5. "match_all": {}
  6. },
  7. "aggs": {
  8. "ageAgg": {
  9. "terms": {
  10. "field": "age",
  11. "size": 100
  12. },
  13. "aggs": {
  14. "genderAgg": {
  15. "terms": {
  16. "field": "gender.keyword",
  17. "size": 10
  18. },
  19. "aggs": {
  20. "genderBalanceAvg": {
  21. "avg": {
  22. "field": "balance"
  23. }
  24. }
  25. }
  26. },
  27. "ageBalanceAvg": {
  28. "avg": {
  29. "field": "balance"
  30. }
  31. }
  32. }
  33. }
  34. },
  35. "size": 0
  36. }

Mapping-映射

介绍

Mapping是用来定义一个文档(document),以及它所包含的属性(field)是如何存储和索引的。

比如,使用mapping来定义:

  • 哪些字符串属性应该被看做全文本属性(full text fields);
  • 哪些属性包含数字,日期或地理位置;
  • 文档中的所有属性是否都被索引(all 配置);
  • 日期的格式;
  • 自定义映射规则来执行动态添加属性;

新版本改变

ElasticSearch7-去掉type概念

  1. 关系型数据库中两个数据的表示是独立的,即使他们里面有相同名称的列也不影响使用,但ES中不是这样的。elasticsearch是基于Lucene开发的搜索引擎,而ES中不同type下名称相同的filed最终在Lucene中的处理方式是一样
    • 两个不同type下的两个user_name,在ES同一个索引下其实被认为是同一个filed,你必须在两个不同的type中定义相同的filed映射。否则,不同type中的相同字段名称就会在处理中出现冲突的情况,导致Lucene处理效率下降。
    • 去掉type就是为了提高ES处理数据的效率。
  1. Elasticsearch 7.x URL中的type参数为可选。比如,索引一个文档不再要求提供文档类型。
  2. Elasticsearch 8.x 不再支持URL中的type参数。

解决:

  1. 将索引从多类型迁移到单类型,每种类型文档一个独立索引
  2. 将已存在的索引下的类型数据,全部迁移到指定位置即可。详见数据迁移

字段类型

核心类型

字符串( string ) text, keyword
数字类型( Numeric ) long, integer, short, byte, double, float,half_float,scaled_float
日期类型( Date ) date
布尔类型( Boolean ) boolean
二进制类型( binary ) binary

复合类型

数组类型( Array ) Array支持不针对特定的类型
对象类型( Object) object用于单JSON对象
嵌套类型(Nested ) nested用于JSON对象数组

地理类型(Geo)

地理坐标( Geo-points ) geo_ point用于描述经纬度坐标
地理图形( Geo-Shape ) geo_ shape用于描述复杂形状,如多边形

特定类型

IP类型 ip用于描述ipv4和ipv6地址
补全类型( Completion ) completion提供自动完成提示
令牌计数类型( Token count ) token_ count 用于统计字符串中的词条数量
附件类型( attachment ) 参考mapper-attachements插件,支持将附件如Microsoft Office格式,Open Document格式,ePub, HTML 等等索引为attachment数据类型。
抽取类型( Percolator ) 接受特定领域查询语言(query-dsI) 的查询

多字段

通常用于为不同目的用不同的方法索引同一个字段。例如,string 字段可以映射为一个text字段用于全文检索,同样可以映射为一个keyword字段用于排序和聚台。另外,你可以使用standard analyzer, english analyzer, french analyzer 来索引一个text字段

这就是muti-fields的目的。大多数的数据类型通过felds参数来支持muti-fields.

映射操作

创建索引映射

创建索引并指定属性的映射规则(相当于新建表并指定字段和字段类型)

  1. PUT /my_index
  2. {
  3. "mappings": {
  4. "properties": {
  5. "age": {"type": "integer"},
  6. "email": {"type": "keyword"},
  7. "name": {"type": "text"}
  8. }
  9. }
  10. }

查看映射

  1. GET my_index/_mapping

为映射添加新的字段

  1. PUT my_index/_mapping
  2. {
  3. "properties": {
  4. "employee-id": {
  5. "type": "keyword",
  6. "index": false
  7. }
  8. }
  9. }

更新映射

对于已经存在的映射字段,我们不能更新。因为一旦修改,会导致相关数据的检索规则发生变化,那样会产生问题,所以想要更新必须要创建新的索引进行数据迁移。

数据迁移

先创建一个新索引,指定好正确的映射关系,使用reindex将数据迁移到新的索引中

1、创建新索引

  1. PUT /newbank
  2. {
  3. "mappings": {
  4. "properties": {
  5. "account_number": {
  6. "type": "long"
  7. },
  8. "address": {
  9. "type": "text"
  10. },
  11. "age": {
  12. "type": "integer"
  13. },
  14. "balance": {
  15. "type": "long"
  16. },
  17. "city": {
  18. "type": "keyword"
  19. } ,
  20. "email": {
  21. "type": "keyword"
  22. },
  23. "employer": {
  24. "type": "keyword"
  25. },
  26. "firstname": {
  27. "type": "text"
  28. },
  29. "gender": {
  30. "type": "keyword"
  31. },
  32. "lastname": {
  33. "type": "text",
  34. "fields": {
  35. "keyword": {
  36. "type": "keyword",
  37. "ignore_above": 256
  38. }
  39. }
  40. },
  41. "state": {
  42. "type": "keyword"
  43. }
  44. }
  45. }
  46. }

2、数据迁移

  1. POST _reindex
  2. {
  3. "source": {
  4. "index":"bank",
  5. "type": "account"
  6. },
  7. "dest": {
  8. "index": "newbank"
  9. }
  10. }

3、查看结果

  1. GET newbank/_search

Elasticsearch 进阶检索 - 图5