Elasticsearch查询操作(一)

// 准备数据
PUT /shop/goods/1
{
 "name": "2017新款女装冬季外套ulzzang棉袄中长款棉衣韩版百搭棉服面包服",
 "desc": "",
 "price": 268,
 "quantity": 9267,
 "colors": [
   "绿色",
   "黑色"
 ],
 "is_discount": true,
 "create_date": "2018-01-31 12:10:30",
 "ip_addr": "192.168.10.1",
 "location": "39.92733,116.39507",
 "merchant": {
   "id": 999,
   "shop_name": "阿依莉旗舰店"
 },
 "params": [
   {
     "id": 1,
     "label": "型号",
     "value": "A30566"
   },
   {
     "id": 2,
     "label": "品牌",
     "value": "阿依莉"
   }
 ],
 "activity": "买一送一"
}

PUT /shop/goods/2
{
  "name": "2018春季长袖t恤女加绒加厚圆领宽松套头毛衣女装韩版学生毛线衣",
  "price": 108,
  "quantity": 268,
  "colors": [
    "白蓝红",
    "红白黑"
  ],
  "is_discount": false,
  "create_date": "2017-01-31 12:10:30",
  "ip_addr": "192.168.10.1",
  "location": "39.92733,116.39507",
  "merchant": {
    "id": 6666,
    "shop_name": "美特斯邦威旗舰店"
  },
  "params": [
    {
      "id": 1,
      "label": "型号",
      "value": "HWT8030"
    },
    {
      "id": 2,
      "label": "品牌",
      "value": "美特斯邦威"
    }
  ]
}

PUT /account/users/1
{
   "username": "xiaoming",
   "nickname": "小明的老师",
   "age": 6,
   "height": 1.68,
   "birthday": "2017-01-31",
   "hobbies": ["吃", "喝", "嫖", "赌"]
}

PUT /accounts/users/1
{
   "username": "teacher",
   "nickname": "谁能求姐",
   "age": 6,
   "height": 1.68,
   "birthday": "2017-01-31",
   "hobbies": ["批评小明"]
}

注意:_search即支持GET也支持POST

GET /_search  // 空查询:查询所有索引下的所有文档
GET /{index}/_search       // 查询某个索引下的前10条文档
GET /{index}/{type}/_search  // 查询某个索引下某个类型的前10条文档

// 返回结果
took字段表示该操作的耗时(单位为毫秒),
timed_out字段表示是否超时,
_shards:在查询中参与分片的总数,以及这些分片成功了多少个失败了多少个
total:返回记录数,本例是2条。
max_score:最高的匹配程度,本例是1.0。
hits:返回的记录组成的数组。
返回的记录中,每条记录都有一个_score字段,表示匹配的程序,默认是按照这个字段降序排列。 

多索引,多类型
GET /{index1},{index2}/_search  // 查询多个索引下的文档
GET /{index*}/_search           // 索引支持*号通配符
GET /{index*},{index*}/_search
GET /_all/_search  // 和GET /_search效果一样,_all:表示所有索引

GET /{index}/{type1},{type2}/_search
// 示例
GET /_search
GET /shop/_search
GET /shop/goods/_search
POST /shop/goods/_search
GET /shop,account/_search
GET /account*/_search
GET /account*,sho*/_search
GET /_all/_search
GET /shop/goods,products/_search

查询字符串

查询字符串:就是在_search上使用GET参数的形式对search进行查询过滤,即将参数追加到路径上,此种方式有局限性,不够灵活

  • q: 通过加号+来指定查询中的某个字段必须包含某个值,默认是加号,通过减号-来指定文档中不能包含某个值,使用冒号将字段和值分隔,如 q=last_name:Smith,类似于关系型数据库中的where中的 like和not like 操作,
  • _source:用于指定要查询的字段,默认会返回文档中的所有字段,多个字段用逗号分隔
  • size: 设置search是返回的消息的条数,默认是10
  • from: 设置跳过的页数,默认是0,可以通过from和size来达到分页的目的
  • sort: 指定对那个字段进行什么排序,默认是按照相关性评分来降续排序的_score, 例如sort=date:desc&sort=_score
  • version: 版本号,用于更新和删除操作,当文档的版本等于指定的版本号时才能正常执行,否则会返回409 版本冲突 (乐观并发控制)
  • ersion_type=external 用于创建、修改、删除操作 外部版本号:当使用外部版本号是es会检查版本号是否比_version值小,如果小的话就正常执行,并将_version的值更改为外部的版本号, 例如version=5&version_type=external
  • timeout=10ms 指定超时时间,默认单位是毫秒ms,也可以指定秒s,例如1s
  • retry_on_conflict=n 参数来设置自动完成这项请求的次数,它的默认值是0,失败前重新尝试n次
  • scroll=1m 游标查询,保持游标查询窗口一分钟
// q好像对中文查询不出啦???可以通过其他方式进行查询
// 查询字段包含的字符串q=filed:value, 类似于SQL中的where last_name like '%Smith%'
GET /{index}/{type}/_search?q=last_name:Smith                     

// 加号+:表示必须存在,每部分都是包含的意思, 类似于SQL中的where fist_name like '%join%' and like '%Smith%'
// + 前缀表示必须与查询条件匹配。类似地, - 前缀表示一定不与查询条件匹配。
// 没有 + 或者 - 的所有其他条件都是可选的,类似于or——匹配的越多,文档就越相关
GET /{index}/{type}/_search?q=fist_name:join+last_name:Smith'    

// -号代表不包含, 类似于SQL中的 where name not like '%join%'   
GET /{index}/{type}/_search?q=-name:join   

// name包含join但tweet不包含jmary的, 类似于SQL中的 where name like '%join%' and tweet not like '%mary%'                     
GET /{index}/{type}/_search?q=name:join+-tweet:mary     

// 查询所有索引所有类型所有字段中包含mary关键字的文档, _all:可以代表所有索引或者所有类型或者所有字段,     
// 每个文档都有一个隐形的_all字段,它的数据类型是文本型,它的值是以空格的形式将文档的所有字段的值拼接起来, 例如一个文档有三个值 age: 15, name:zhangsan, birthday:2018-09-15, 那么_all的值为“15 zhangsan 2018-09-15”
// _all会被分词,如果字段中包含日期,例如2018-09-15会被分析成2018,09, 15 三个词条(token)  
GET /{index}/{type}/_search?q=_all:mary  

// 如果不指定字段则默认是_all字段, _all字段是String类型                       
GET /{index}/{type}/_search?q=mary   

POST /shop/goods/_search?_source=name,price

POST /shop/goods/_search?timeout=10ms   

POST /shop/goods/_search?from=0&size=5    

POST /shop/goods/_search?sort=create_date:desc&sort=_score                    

查询表达式DSL

使用查询领域特定语言(Query Domain Specific Language) 简称为DSL, 需要使用JSON作为主体,请求体查询

  • query

    • match:模糊匹配,类似于SQL中的like,示例{ “match” : { “field” : “keyword” }},
    • match_all:简单的匹配所有文档 {“match_all”: {}}
    • match_phrase: 对于短语或者段落进行精确匹配
    • match_phrase_prefix
    • multi_match: 在多个字段上反复执行相同查询
    • bool 用于表示复合语句,用于组合多个查询语句;将多查询组合成单一查询
      • must 必须匹配这些条件才能被包含进来,表示并且的关系
      • must_not 必须不 匹配这些条件才能被包含进来
      • should 如果满足这些语句中的任意语句,将增加 _score ,否则无任何影响。它们主要用于修正每个文档的相关性得分。
      • minimum_should_match:控制需要匹配的 should 语句的数量, 它既可以是一个绝对的数字,又可以是个百分比, 如 minimum_should_match: 2 或者 “minimum_should_match”: “75%”
      • filter 必须匹配,但它以不评分、过滤模式来进行。这些语句对评分没有贡献,只是根据过滤标准来排除或包含文档, filter只是简单的数据过滤,并不影响评分,因filter不计算评分,所以性能更好,请尽可能多的使用过滤式查询
        • exists 查找包含某个字段的文档
    • range 范围,可以使用大于gt、大于等于gte、小于lt、小于等于lte作为查询条件,可用于数字、日期类型、字符串
    • term 精确查询,对数值,日期,布尔,not_analyzed确切值字符串
    • terms 指定多个匹配值,如果字段包含其中的任何一个,都会返回文档,类似于SQL中的IN 操作
    • constant_score: 恒定分数,它将一个不变的常量评分应用于所有匹配的文档
    • wildcard: 通配符, ? 匹配任意字符, * 匹配 0 或多个字符
    • fuzzy: 模糊查询
    • dis_max:分离 最大化查询(Disjunction Max Query)
    • nested : 用于操作嵌套类型
  • highlight 高亮,匹配的结果会被 HTML字符包裹住,需要指定匹配的字段

  • aggs 聚合操作,类似SQL中的Group By
  • sort 排序
  • from 偏移量,类似于SQL中limit中的offset
  • size 返回数量,类似于SQL中limit中的count,可以通过from,size来达到分页的效果
// 使用DSL查询肯能条件很多,比较复杂,可以通过使用验证API来检查一个查询是否有效
GET /{index}/{type}/_validate/query?explain 
{  
   "query": {  
      ... 
    }  
} 

数据准备

DELETE /shop/goods/_all 删除所有文档

match 匹配查询

全文检索方式查询,类似于关系型数据库中的like操作,使用match时需要指定对那个字段进行全文检索,以及对应的关键字, 关键字可以指定一个也可以指定多个,指定多个时表示或者的关系 类似于SQL中的or的功能。语法:
{ "match" : { "field" : "keyword" }} 类似于SQL中的where filed like ‘%keyword%’
{ "match" : { "field" : "keyword1 keyword2" }} 类似于SQL中的where field like ‘%keyword1%’ or field like ‘%keyword2%’

示例:

// 查询name中包含“女装”的文档

GET /shop/goods/_search 
{
  "query": {
    "match": {
      "name": "女装"
    }
  }
}

// 多词查询 :使用空格隔离多个单词
// 查询name中包含“外套” 或者or 包含 “休闲” 的文档,多个关键字使用空格分隔,如果不指定operator默认是or
GET /shop/goods/_search 
{
  "query": {
    "match": {
      "name": "外套 休闲"
    }
  }
}

// "name": "外套 休闲" or 等价于bool中的should
GET /shop/goods/_search 
{
  "query": {
    "bool": {
      "should": [
        "match": { "name": "外套" },
        "match": { "name": "休闲" },
        ]
    }
  }
}

// 查询name中包含“外套” 并且 包含 “休闲” 的文档,多个关键字使用空格分隔
GET /shop/goods/_search 
{
  "query": {
    "match": {
      "name": "外套 休闲",
      "operator": "and"
    }
  }
}

// "name": "外套 休闲" and 等价于bool中的must
GET /shop/goods/_search 
{
  "query": {
    "bool": {
      "must": [
        "match": { "name": "外套" },
        "match": { "name": "休闲" },
        ]
    }
  }
}

// 多词查询中使用or只需要满足一个即可,要求太低,使用and又必须所有词项都必须满足,要求又太高,
// 使用minimum_should_match折中一下,最小匹配:可以指定一个百分比,
// 例如指定4个词项,一个是词项是25%,设置成50%就是至少要满足2个词项
GET /shop/goods/_search
{
  "query": {
    "match": {
      "name": {
        "query": "春季 长袖 圆领 学生",
        "minimum_should_match": "50%"
      }
    }
  }
}

// 效果和上面一样,等价的
GET /shop/goods/_search
{
   "query" : {
      "bool": {
        "filter": {
          "bool" : {
              "should" : [
                 { "term" : {"name" : "春季"}}, 
                 { "term" : {"name" : "长袖"}}, 
                 { "term" : {"name" : "圆领"}}, 
                 { "term" : {"name" : "学生"}}
              ],
              "minimum_should_match": 2
           }
        }
      }
   }
}

// 查询日期
GET /shop/goods/_search 
{
  "query": {
    "match": {
      "create_date": "2018-01-31"
    }
  }
}

match一般用于用引号括起来的值,如文本,日期,如果将match用于布尔或者数字等数据类型就变成精确匹配了,而不是全文检索或者模糊匹配了
如果在一个精确值的字段上使用match,例如数字、日期、布尔或者一个 not_analyzed 字符串字段,那么它将会精确匹配给定的值:

match_all

简单的匹配所有文档

GET /shop/goods/_search 
{
  "query": {
    "match_all": {}
  }
}

// 上面简写成这样,效果是一样的 
GET /shop/goods/_search 
{}

// 同样也可以去掉{},更加简洁
GET /shop/goods/_search 

match_phrase

对于短语或者段落进行精确匹配,

// match如果对一小段文本进行查询,match首先对字段值进行分词,然后对分词进行匹配,相当于SQL中的name like '%女装%' or name like '%冬季%' or name like '%外套%'
GET /shop/goods/_search 
{
  "query": {
    "match": {
      "name": "女装冬季外套"
    }
  }
}


GET /shop/goods/_search 
{
  "query": {
    "match_phrase": {
      "name": "女装冬季外套"
    }
  }
}

// slop:让相对词序位置不那么严格
// 注意上面使用的是“女装冬季外套”,而现在使用的是“套女装冬季”, slop:允许每个词放宽的间隔
// 尽管词语的顺序不正确,查询仍然能匹配,因为我们为它设置了足够高的slop值使匹配时的词序有更大的灵活性。
GET /shop/goods/_search 
{
  "query": {
    "match_phrase": {
      "name": {
            "query": "外套女装冬季",
            "slop":  10
        }
    }
  }
}

match_phrase_prefix

match_phrase_prefix与match_phrase是一样的,只是它允许在文本的最后一项中使用前缀匹配。

可以用于即时搜索(instant search) 或 输入即搜索(search-as-you-type),例如,如果用户输入 johnnie walker bl ,我们希望在它们完成输入搜索条件前就能得到:Johnnie Walker Black Label 和 Johnnie Walker Blue Label 。

GET /shop/goods/_search 
{
  "query": {
    "match_phrase_prefix": {
      "name": "女装冬季外套"
    }
  }
}


// slop:让相对词序位置不那么严格
// 注意上面使用的是“女装冬季外套”,而现在使用的是“套女装冬季”, slop:允许每个词放宽的间隔
// 尽管词语的顺序不正确,查询仍然能匹配,因为我们为它设置了足够高的slop值使匹配时的词序有更大的灵活性。
GET /shop/goods/_search 
{
  "query": {
    "match_phrase_prefix": {
      "name": {
            "query": "外套女装冬季",
            "slop":  10
      }
    }
  }
}

prefix 查询存在严重的资源消耗问题,短语查询的这种方式也同样如此。前缀 a 可能会匹配成千上万的词,这不仅会消耗很多系统资源,而且结果的用处也不大。

索引时输入即搜索

## edge_ngram 自定义过滤器、分词器
PUT /my_index
{
    "settings": {
        "number_of_shards": 1, 
        "analysis": {
            "filter": {
                "autocomplete_filter": { 
                    "type":     "edge_ngram",
                    "min_gram": 1,
                    "max_gram": 20
                }
            },
            "analyzer": {
                "autocomplete": {
                    "type":      "custom",
                    "tokenizer": "standard",
                    "filter": [
                        "lowercase",
                        "autocomplete_filter" 
                    ]
                }
            }
        }
    }
}

## 测试分词
GET /my_index/_analyze
{
  "analyzer": "autocomplete",
  "text": "quick brown"
}

PUT /my_index/_mapping/my_type
{
    "my_type": {
        "properties": {
            "name": {
                "type":     "text",
                "analyzer": "autocomplete",  ## 使用自定义的分词器
                "search_analyzer": "standard" ## 配置查询对应的分词器
            }
        }
    }
}

POST /my_index/my_type/_bulk
{ "index": { "_id": 1            }}
{ "name": "Brown foxes"    }
{ "index": { "_id": 2            }}
{ "name": "Yellow furballs" }

## 搜索
GET /my_index/my_type/_search
{
    "query": {
        "match": {
            "name": {
                "query":    "brown fo"
            }
        }
    }
}

multi_match

多个字段上使用相同的值作为查询条件

GET /shop/goods/_search
{
  "query": {
    "multi_match": {
      "query": 268,
      "fields": ["price", "quantity"]
    }
  }
}

// 两者效果相同
GET /shop/goods/_search
{
  "query": {
    "bool": {
      "should": [
        { "term": { "price": { "value": 268 } } },
        { "term": { "quantity": { "value": 268 } } }
      ]
    }
  }
}

// 查询字段名称的模糊匹配
// 字段名称可以用模糊匹配的方式给出:任何与模糊模式正则匹配的字段都会被包括在搜索条件中,
例如可以使用以下方式同时匹配 book_title 、 chapter_title 和 section_title (书名、章名、节名)这三个字段:

{
    "multi_match": {
        "query":  "Quick brown fox",
        "fields": "*_title"
    }
}

// 提升单个字段的权重
// 可以使用 ^ 字符语法为单个字段提升权重,在字段名称的末尾添加 ^boost ,其中 boost 是一个浮点数:
// chapter_title 这个字段的 boost 值为 2 ,而*_title 字段的默认 boost 值为 1
{
    "multi_match": {
        "query":  "Quick brown fox",
        "fields": [ "*_title", "chapter_title^2" ] (1)
    }
}

constant_score 常量分数

通常当查找一个精确值的时候,我们不希望对查询进行评分计算。只希望对文档进行包括或排除的计算,所以我们会使用 constant_score 查询以非评分模式来执行 term 查询并以一作为统一评分。

它将一个不变的常量评分应用于所有匹配的文档。它被经常用于你只需要执行一个 filter 而没有其它查询(例如,评分查询)的情况下。可以使用它来取代只有 filter 语句的 bool 查询。在性能上是完全相同的,但对于提高查询简洁性和清晰度有很大帮助. 这种方式可以用来取代只有 filter 语句的 bool 查询

GET /shop/goods/_search 
{
  "query": {
    "constant_score": {
      "filter": {
        "term": {
          "price": 268.00
        }
      }
    }
  }
}

查询置于 filter 语句内不进行评分或相关度的计算,所以所有的结果都会返回一个默认评分 1

prefix 前缀查询

前缀查询:要查询的字段必须没有分词

默认状态下, prefix 查询不做相关度评分计算,它只是将所有匹配的文档返回,并为每条结果赋予评分值 1 。它的行为更像是过滤器而不是查询。 prefix 查询和 prefix 过滤器这两者实际的区别就是过滤器是可以被缓存的,而查询不行。

prefix 查询或过滤对于一些特定的匹配是有效的,但使用方式还是应当注意。当字段中词的集合很小时,可以放心使用,但是它的伸缩性并不好,会对我们的集群带来很多压力。可以使用较长的前缀来限制这种影响,减少需要访问的量。

PUT /my_index
{
    "mappings": {
        "address": {
            "properties": {
                "postcode": {
                    "type":  "keyword"
                }
            }
        }
    }
}

PUT /my_index/address/1
{ "postcode": "W1V 3DG" }

PUT /my_index/address/2
{ "postcode": "W2F 8HW" }

PUT /my_index/address/3
{ "postcode": "W1F 7HW" }

PUT /my_index/address/4
{ "postcode": "WC1N 1LZ" }

PUT /my_index/address/5
{ "postcode": "SW5 0BE" }

// prefix 查询
GET /my_index/address/_search
{
  "query": {
    "prefix": {
      "postcode": {
        "value": "W1"
      }
    }
  }
}

wildcard 和 regexp

与 prefix 前缀查询的特性类似, wildcard 通配符查询也是一种底层基于词的查询,与前缀查询不同的是它允许指定匹配的正则式。它使用标准的 shell 通配符查询: ? 匹配任意字符, * 匹配 0 或多个字符。

GET /my_index/address/_search
{
    "query": {
        "wildcard": {
            "postcode": "W?F*HW" 
        }
    }
}

// 词必须以 W 开头,紧跟 0 至 9 之间的任何一个数字,然后接一或多个其他字符
GET /my_index/address/_search
{
    "query": {
        "regexp": {
            "postcode": "W[0-9].+" 
        }
    }
}

wildcard 和 regexp 查询的工作方式与 prefix 查询完全一样,它们也需要扫描倒排索引中的词列表才能找到所有匹配的词,然后依次获取每个词相关的文档 ID ,与 prefix 查询的唯一不同是:它们能支持更为复杂的匹配模式。

这也意味着需要同样注意前缀查询存在性能问题,对有很多唯一词的字段执行这些查询可能会消耗非常多的资源,所以要避免使用左通配这样的模式匹配(如: *foo 或 .*foo 这样的正则式)。

数据在索引时的预处理有助于提高前缀匹配的效率,而通配符和正则表达式查询只能在查询时完成,尽管这些查询有其应用场景,但使用仍需谨慎。

prefix 、 wildcard 和 regexp 查询是基于词操作的,如果用它们来查询 analyzed 字段,它们会检查字段里面的每个词,而不是将字段作为整体来处理。


range

用于查询一个区间,一般用于日期和数值,支持 gt、gte、lt、lte, 示例{“range”: { “age”: { “gte”: 20, “lt”:30 }}} 类似于SQL中的 wher age >= 20 and age < 30

GET /shop/goods/_search
{
  "query": {
    "range": {
      "price": {
        "gt": 200,
        "lte": 500
      }
    }
  }
}

// 日期类型
GET /shop/goods/_search
{
  "query": {
    "range": {
      "create_date": {
        "gt" : "2014-01-01 00:00:00",
        "lt" : "2014-01-07 00:00:00"
      }
    }
  }
}

// 日期计算:过去一小时
GET /shop/goods/_search
{
  "query": {
    "range": {
      "create_date": {
        "gt" : "now-1h"
      }
    }
  }
}

// 日期计算:早于 2014 年 1 月 1 日加 1 月(2014 年 2 月 1 日 零时)
GET /shop/goods/_search
{
  "query": {
    "range": {
      "create_date": {
        "gt" : "2014-01-01 00:00:00",
        "lt" : "2014-01-01 00:00:00||+1M"
      }
    }
  }
}

// 作用于字符串,性能相对较慢
"range" : {
    "title" : {
        "gte" : "a",
        "lt" :  "b"
    }
}

term

精确查询:用于精确值匹配,对数值,日期,布尔,not_analyzed确切值字符串, term 查询对于输入的文本不 分析 ,所以它将给定的值进行精确查询。

GET /shop/goods/_search
{
  "query": {
    "term": {
      "is_discount": {
        "value": true
      }
    }
  }
}

terms

同term查询,但是它允许指定多个匹配值,一般用于数组,如果字段包含其中的任何一个,都会返回文档, 类似于where tag IN (‘value1’, ‘value2’, ‘value3’) 例如:{ “terms”: { “tag”: [ “search”, “full_text”, “nosql” ] }}

GET /shop/goods/_search
{
  "query": {
    "terms": {
      "colors": [
        "白蓝红",
        "绿色"
      ]
    }
  }
}

exists

对于相同类型的文档,可能有的文档有某个字段,有的文档没有某个字段,查找包含或者不包含某个字段的文档, 例如: {“exists”: { “field”: “title” }} ,exists 用于查找那些指定字段中是否有值 , 相当于SQL中的IS NOT NULL

null, [] (空数组)和 [null] 所有这些都是等价的,它们无法存于倒排索引中

这些查询经常用于某个字段有值的情况和某个字段缺值的情况。

// 存在某个字段
GET /shop/goods/_search
{
  "query": {
    "bool": {
      "filter": {
        "exists": {
          "field": "activity"
        }
      }
    }
  }
}

// 不存在某个字段
GET /shop/goods/_search
{
  "query": {
    "bool": {
      "must_not": {
        "exists": {
          "field": "activity"
        }
      }
    }
  }
}

POST /my_index/posts/_bulk
{ "index": { "_id": "1"              }}
{ "tags" : ["search"]                }  
{ "index": { "_id": "2"              }}
{ "tags" : ["search", "open_source"] }  
{ "index": { "_id": "3"              }}
{ "other_field" : "some data"        }  
{ "index": { "_id": "4"              }}
{ "tags" : null                      }  
{ "index": { "_id": "5"              }}
{ "tags" : ["search", null]          }

以上文档集合中 tags 字段对应的倒排索引如下:
Token DocIDs
open_source 2
search 1,2,5

1. tags 字段有 1 个值。
2. tags 字段有 2 个值。
3. tags 字段缺失。
4. tags 字段被置为 null 。
5. tags 字段有 1 个值和 1 个 null 。



// 1,2,5 满足条件
GET /my_index/posts/_search
{
    "query" : {
        "constant_score" : {
            "filter" : {
                "exists" : { "field" : "tags" }
            }
        }
    }
}

highlight:高亮

匹配的结果会被 HTML字符包裹住,需要指定匹配的字段,”highlight”: {“fields” : {“about” : {}}}

// 高亮: 匹配的结果会被 <em></em> HTML字符包裹住:
curl -i -H 'Content-Type: application/json'  -XGET 'http://localhost:9200/megacorp/employee/_search' -d '
{
    "query" : {
        "match_phrase" : {
            "about" : "rock climbing"
        }
    },
    "highlight": {
        "pre_tags" : ["<font color='red'>"],
        "post_tags" : ["</font>"],
        "fields" : {
            "about" : {}
        }
    }
}'

sort

排序,可以指定一个或者多个字段排序,多个字段使用数组包围,例如:”sort”: { “date”: { “order”: “desc” }}

// 排序,默认情况下是按照相关性评分排序的,最相关的文档排在最前, 默认按_score排序的
// 多级排序,使用date, _score排序
GET /_search  
{  
    "query" : {  
        "bool" : {  
            "must":   { "match": { "tweet": "manage text search" }},  
            "filter" : { "term" : { "user_id" : 2 }}  
        }  
    },  
    "sort": [  
        { "date":   { "order": "desc" }},  
        { "_score": { "order": "desc" }},
        { "ids" : { "order": "asc", "mode":  "min"}}  
    ]  
}  

mode:一般用于数组,可以使用min 、 max 、 avg 或是 sum,统计计算数组的指定值排序

对字符串排序,sort对字符串排序需要使用到原始值raw,正常情况下文本可能会使用分词器进行分词,而分词器会影响正常的排序,这时可以对同一个字段设置两种类型,对文本设置成text类型,并设置分词器,如果要搜索的话使用text类型字段,然后再为该字段设置一个原始值,该原始值raw字段的fields的数据类型设置为keyword,关键字数据类型是不分词的,不分词的字段可以作为字符串的排序 

// fields 多字段:相当于对同一个字段值起不同的名字,赋予这个字段不同的属性(如类型不同,分词器不同等)
PUT /school
{
  "mappings": {
    "students": {
      "properties": {
        "name": {
          "type": "text",
          "analyzer": "ik_max_word",
          "fields": {
            "raw": {
              "type": "keyword"
            }  
          }
        }
      }
    }
  }
}

// _score 和 max_score 字段都是 null 。计算 _score 的花销巨大,通常仅用于排序; 我们并不根据相关性排序,所以记录 _score 是没有意义的。如果无论如何你都要计算 _score , 你可以将 track_scores 参数设置为 true
GET /school/students/_search 
{
  "query": { "match": { "name": "abc" } }, 
  "sort": [ { "name.raw": { "order": "desc" } } ]
}

// 强制计算评分
GET /school/students/_search 
{
  "track_scores": true,
  "query": { "match": { "name": "abc" } }, 
  "sort": [ { "name.raw": { "order": "desc"} } ]
}

from

偏移量,类似于SQL中limit中的offset

size

返回数量,类似于SQL中limit中的count,可以通过from,size来达到分页的效果

GET /shop/goods/_search
{
  "from": 0,
  "size": 20
}

游标查询Scroll

使用from, size做分页不能分页太深,太深对性能营销较大,一般获取前1000条数据就算深了,游标查询用于解决深度分页带来的性能问题。

scroll 查询可以用来对Elasticsearch有效地执行大批量的文档查询,而又不用付出深度分页那种代价。游标查询允许我们 先做查询初始化,然后再批量地拉取结果。 这有点儿像传统数据库中的 cursor 。游标查询会取某个时间点的快照数据,查询初始化之后索引上的任何变化会被它忽略。 它通过保存旧的数据文件来实现这个特性,结果就像保留初始化时的索引 ‘视图’ 一样。

深度分页的代价根源是结果集全局排序,如果去掉全局排序的特性的话查询结果的成本就会很低。 游标查询用字段_doc来排序。 这个指令让 Elasticsearch 仅仅从还有结果的分片返回下一批结果。启用游标查询可以通过在查询的时候设置参数 scroll 的值为我们期望的游标查询的过期时间,游标查询的过期时间会在每次做查询的时候刷新,所以这个时间只需要足够处理当前批的结果就可以了,而不是处理查询结果的所有文档的所需时间。 这个过期时间的参数很重要,因为保持这个游标查询窗口需要消耗资源,所以我们期望如果不再需要维护这种资源就该早点儿释放掉。 设置这个超时能够让 Elasticsearch 在稍后空闲的时候自动释放这部分资源。

// 保持游标查询窗口一分钟
// 关键字 _doc 是最有效的排序顺序。
GET /shop/goods/_search?scroll=1m
{
  "query": {"match_all": {}},
  "sort": ["_doc"],
  "size": 1000
}

// 这个查询的返回结果包括一个字段 _scroll_id, 它是一个base64编码的长字符串 。 现在我们能传递字段 _scroll_id 到 _search/scroll 
{
  "_scroll_id": "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAAMoFmQ0clZDNEg4UWYtYTBzVTg0QWRFdmcAAAAAAAADKRZkNHJWQzRIOFFmLWEwc1U4NEFkRXZnAAAAAAAAAyoWZDRyVkM0SDhRZi1hMHNVODRBZEV2ZwAAAAAAAAMrFmQ0clZDNEg4UWYtYTBzVTg0QWRFdmcAAAAAAAADLBZkNHJWQzRIOFFmLWEwc1U4NEFkRXZn",
  "took": 1,
  "timed_out": false,
  ...
}

// 查询接口获取下一批结果:
GET /_search/scroll
{
  "scroll": "1m",
  "scroll_id": "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAAKbFmQ0clZDNEg4UWYtYTBzVTg0QWRFdmcAAAAAAAACnBZkNHJWQzRIOFFmLWEwc1U4NEFkRXZnAAAAAAAAAp0WZDRyVkM0SDhRZi1hMHNVODRBZEV2ZwAAAAAAAAKeFmQ0clZDNEg4UWYtYTBzVTg0QWRFdmcAAAAAAAACnxZkNHJWQzRIOFFmLWEwc1U4NEFkRXZn"
}

这个游标查询返回的下一批结果。 尽管我们指定字段 size 的值为1000,我们有可能取到超过这个值数量的文档。 当查询的时候, 字段 size 作用于单个分片,所以每个批次实际返回的文档数量最大为 size * number_of_primary_shards.

注意游标查询每次返回一个新字段 _scroll_id。每次我们做下一次游标查询, 我们必须把前一次查询返回的字段 _scroll_id 传递进去。 当没有更多的结果返回的时候,我们就处理完所有匹配的文档了。

bool

布尔查询,这是一个很重要的查询,它可以将其它多种查询封装成一个大的查询,可以使用逻辑操作符(类似于sql中的and、not、or)来组装各个条件, 这是个复合过滤器(compound filter) ,它可以接受多个其他过滤器作为参数,并将这些过滤器结合成各式各样的布尔(逻辑)组合

用于表示复合语句,用于组合多个查询语句;将多查询组合成单一查询,bool可以放到query下面,也可以嵌套在某个子条件(must、should、must_not)里, 通过嵌套可以构造出更加复杂的过滤条件。

  • must: 必须匹配这些条件才能被包含进来。 表示并且的关系,与 SQL中的AND 等价,例如{"must": [{"match": {"desc": "xxx"}}, {"term": { "quantity": 999}}]},类似于SQL中的where desc like '%xxx%' and quantity = 999
  • must_not: 必须不匹配这些条件才能被包含进来, 是对must的取反操作,与SQL中的 != 或者<> 等价, where status != 0
  • should 至少有一个语句要匹配, 与 SQL中的 OR 等价,是一个数组,可以有多个值,如果满足这些语句中的任意语句,将增加_score的值, should的作用:or逻辑,如果满足条件评分_score更高
  • filter:必须匹配,以过滤模式来进行。这些语句对评分没有贡献,只是根据过滤标准来排除或包含文档, filter只是简单的数据过滤,并不影响评分
  • minimum_should_match

bool 查询会为每个文档计算相关度评分 _score ,再将所有匹配的 must 和 should 语句的分数 _score 求和,最后除以 must 和 should 语句的总数。

must_not 语句不会影响评分;它的作用只是将不相关的文档排除。

所有must语句必须匹配,所有must_not语句都必须不匹配,经测试至少有一个should需要匹配的(在should中写两个条件,每天条件都不满足条件,结果没有任何文档满足),当没有 must 语句的时候,至少有一个 should 语句必须匹配。

GET /shop/goods/_search 
{
  "query": {
    "bool": {
      "must": [
        {"term": {
          "quantity": {
            "value": 999
          }
        }}
      ], 
      "must_not": [
        {
          "term": {
            "quantity": {
              "value": 9267
            }
          }
        }
      ],
      "should": [
        {
          "term": {
            "is_discount": {
              "value": true
            }
          }
        }
      ],
      "filter": {
        "range": {
          "price": {
            "gte": 7777,
            "lte": 9999
          }
        }
      }
    }
  }
}
// filter中也可以嵌套bool查询,这样内部的bool查询就不参与评分了
// bool中的must must_not should 等会计算评分的,如果不希望计算评分,可将bool放入到filter中,这样既不计算评分又可以使用bool中的逻辑
// 直接使用bool中的filter和将bool再次嵌入到filter中都不计算评分
GET /shop/goods/_search 
{
    "query": {
        "bool": {
              "must":     { "match": { "title": "how to make millions" }},
              "must_not": { "match": { "tag":   "spam" }},
              "should": [
                  { "match": { "tag": "starred" }}
              ],
              "filter": {
                "bool": { 
                    "must": [
                        { "range": { "date": { "gte": "2014-01-01" }}},
                        { "range": { "price": { "lte": 29.99 }}}
                    ],
                    "must_not": [
                        { "term": { "category": "ebooks" }}
                    ]
                }
              }
          }
    }
}


// 就像我们能控制 match 查询的精度 一样,我们可以通过 minimum_should_match 参数控制需要匹配的
// should 语句的数量, 它既可以是一个绝对的数字,又可以是个百分比:
// 这个查询结果会将所有满足以下条件的文档返回: 
// title 字段包含 "brown" AND "fox" 、 "brown" AND "dog" 或 "fox" AND "dog" 。
// 如果有文档包含所有三个条件,它会比只包含两个的文档更相关。
GET /my_index/my_type/_search
{
  "query": {
    "bool": {
      "should": [
        { "match": { "title": "brown" }},
        { "match": { "title": "fox"   }},
        { "match": { "title": "dog"   }}
      ],
      "minimum_should_match": 2 
    }
  }
}

// boost 参数被用来提升一个语句的相对权重( boost 值大于 1 )或降低相对权重( boost 值处于 0 到 1 之间),
// 但是这种提升或降低并不是线性的,换句话说,如果一个 boost 值为 2 ,并不能获得两倍的评分 _score 。
// 通过指定 boost 来控制任何查询语句的相对的权重, boost 的默认值为 1 ,大于 1 会提升一个语句的相对权重。
// 更高的 boost 值为我们带来更高的评分 _score
GET /_search
{
    "query": {
        "bool": {
            "must": {
                "match": {  
                    "content": {
                        "query":    "full text search",
                        "operator": "and"
                    }
                }
            },
            "should": [
                { "match": {
                    "content": {
                        "query": "Elasticsearch",
                        "boost": 3 
                    }
                }},
                { "match": {
                    "content": {
                        "query": "Lucene",
                        "boost": 2 
                    }
                }}
            ]
        }
    }
}

过滤查询:不需要评分,性能更好,对结果进行缓存
评分查询:需要评分,评分比较费力,不对结果进行缓存
如何选择查询与过滤? 通常的规则是,使用查询(query)语句来进行 全文搜索或者其它任何需要影响相关性得分的搜索。除此以外的情况都使用过滤(filters)。

aggs

聚合操作,类似SQL中的Group By, 支持的聚合类型有avg, min, max, sum, rang 等,也可以对地理位置进行聚合

如果要对一个字段进行聚合,要保证这个字段的fielddata设置为true

PUT /{index}/_mapping/{type}
{
  "properties": {
    "FILED": {
      "type": "text",
      "fielddata": true
    }
  }
}
// 统计数组中每个元素出现的次数,中文有问题,现在中文分词是按单个字分词的,估计需要指定对该字段不分词
GET /shop/goods/_search
{
  "aggs": {
    "xxx": {
      "terms": {
        "field": "colors",
        "size": 10
      }
    }
  }
}

// aggs可以嵌套在aggs中使用
// 嵌套聚合,分级汇总,在聚合中可以进行再聚合,意思是对分组的文档进行其他聚合,而不是对聚合结果进行处理
GET /shop/goods/_search
{
  "aggs": {
    "xxx": {
      "terms": {
        "field": "colors",
        "size": 10
      },
      "aggs": {
        "yyy": {
          "avg": {
            "field": "price"
          }
        }
      }
    }
  }
}

_mget

multi-get,通过docs数组作为参数指定多个doc来获取多个文档,每个doc可以分别指定索引、类型、id,文档或者api中必须包含index/type/id

// 路径中不包含index、type、id
GET /_mget 
{
   "docs" : [
      {
         "_index" : "shop",
         "_type" :  "goods",
         "_id" :    2
      },
      {
         "_index" : "account",
         "_type" :  "users",
         "_id" :    1,
         "_source": "nickname"
      }
   ]
}

// 路径中包含index、type, 如果参数中没有指定index、type就使用路径中的,如果参数中明确指定了,就使用参数中的索引和类型
GET /{index}/{type}/_mget
{
   "docs" : [
      { "_id" : 2 },
      { "_type" : "account", "_id" : 1 }
   ]
}

// 路径中指定了索引和类型,通过ids数组指定多个id值
GET /{index}/{type}/_mget'
{
   "ids" : [ "2", "1" ]
}

_bulk

批量操作:将多个操作封装成一个操作,一次执行多个动作(create,index, update以及delete),并返回每个执行结果.
可以通过_bulk来执行批量插入、批量更新等操作

POST _bulk的请求主体的格式稍微有些不同:

{ action: { metadata }}\n
{ request body        }\n
{ action: { metadata }}\n
{ request body        }\n
...

它通过换行符(\n)连接到一起,最后一行也要有\n,每行一定要以换行符(\n)结尾, 包括最后一行 。这些换行符被用作一个标记,可以有效分隔行,这些行不能包含未转义的换行符,因为他们将会对解析造成干扰

  • action 必须是以下选项之一:
    • create:如果文档不存在,那么就创建它, 相当于 PUT /{index}/{type}/{id}/_create
    • index:创建一个新文档或者替换一个现有的文档, 相当于 PUT /{index}/{type}/{id}
    • update:部分更新一个文档, 即局部更新文档中的个别字段,相当于 /{index}/{type}/{id}/_update
    • delete:删除一个文档,删除操作不需要指定请求体,delete操作没有请求体,它紧接着另一个行为;记得最后一个换行符
  • metadata 每个动作需要的参数,json格式的,应该指定被索引、创建、更新或者删除的文档的_index,_type和 _id

每个子请求都是独立执行,因此某个子请求的失败不会对其他子请求的成功与否造成影响。 如果其中任何子请求失败,最顶层的 error 标志被设置为 true ,并且在相应的请求报告出错误明细
这也意味着 bulk 请求不是原子的: 不能用它来实现事务控制。每个请求是单独处理的,因此一个请求的成功或失败不会影响其他的请求

POST /_bulk
{ "create": { "_index": "shop", "_type": "goods", "_id": 123 }}
{ "name":    "My first blog post" }
{ "index":  { "_index": "shop", "_type": "goods" }}
{ "name":    "My second blog post" }
{ "update": { "_index": "shop", "_type": "goods", "_id": 123, "retry_on_conflict" : 3} }
{ "doc" : {"title" : "My updated blog post"} }
{ "delete": { "_index": "shop", "_type": "goods", "_id": 1234 }} 

 

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页