ElasticSearch使用初探

简易搜索

简单搜索是通过查询字符串定义的,查询方式简单,但实现的功能也比较少。

空搜索

GET /_search

响应内容如下

  • total:匹配到的文档总数
  • _score:相关性得分,衡量了文档与查询的匹配程度
  • max_score:指的是所有文档匹配查询中_score的最大值
  • took:整个搜索请求话费的毫秒数
  • shards:参与查询的分片数
  • suffessfull:成功的次数
  • timeout:查询是否超时,查询时可以设置超时时间

    GET /_search?timeout=10ms
    

搜索特定文档

  • 搜索全部文档的请求,默认返回前10个命中的结果

    GET /megacorp/employee/_search?pretty}}}
    
  • 带关键字的查询q=属性:
  • 的查询,可以得到所有属性=value的结果

    GET /megacorp/employee/_search?q=last_name:Smith
    
  • 通过URL路径的方式限定查询的索引和类型范围

    • 例:在索引gb和us的所有类型中搜索

      /gb,us/_search
      
    • 例:在以g或u开头的索引的所有类型中搜索

      /g*,u*/_search
      
    • 例:在索引gb和us的类型为user和tweet中搜索

      /_all/user,tweet/_search
      

每次查询结果都是排序的,但一个搜索请求常常设计多个分片,每个分片生成自己排好序的结果,它们接着需要集中起来排序以确保整体排序正确

查询所有类型为tweet并在tweet字段中包含elasticsearch字符的文档

GET /_all/tweet/_search?q=tweet:elasticsearch

如果查找name字段中包含”john“和tweet字段中包含”mary“的结果,实际的查询结果只需要变为如下:

GET /a_ll/tweet/_search?q=tweet:elasticseach+name:john+tweet:mary

校验查询语句

查询语句可以变的非常复杂,所以我们需要使用validate方法校验查询语句。

GET /gb/tweet/_validate/query
{
    "query":{
        "tweet": {
            "match":"really powerfull"
        }
    }
}

如果是合法语句,会有一个explainations字段为每一个索引索引一段描述,每个索引会有不同的映射关系和分析器:

pretty

在查询url中最后添加上pretty参数,可以使结果非常整洁

get http://10.214.208.166:9200/wiforce-2015.12.20
/_mapping/detected_ap_measurement?pretty

富搜索–结构化查询语句DSL

大多数的参数以JSON格式所容纳而非查询字符串,请求体查询并不仅仅用来处理查询,而且还可以高亮返回结果中的片段,并且给出帮助你的用户找寻最好的结果的相关数据建议。

指定索引和类型

GET /index/type1,type2/_search
{}

当然我们还可以使用fromsize参数进行分页

GET /_search
{
    "from":30,
    "size":10
}

查询关键字

  • query:查询关键字

  • filter: 需要以过滤条件开始,把query语句放到filtered中

在收件箱中查询email中与business opportunity相关的邮件。查询语句为:

GET /_search
{
    "query":{
        "filtered":{
            "filter": {"term": {"folder": "inbox"} }
        }
    }

}
  • term:主要用于精确匹配哪些值,比如数字,日期,布尔值(not_analyzed的字符串)

    {"term": {"age": 26 }}
    
  • terms:允许多个匹配

    {"terms": {"age": [26,1,2,3,4] }}
    
  • match_all:匹配所有的文档

  • match: 查询子句用来更进一步匹配,match的匹配并不是完全匹配,例如tweet中包含elasticsearch字段的

    GET /_search
    {
        "query":{
            "match":{
                "tweet":"elasticsearch"
            }
    }
    
  • bool: 用于合并多个查询子句

    • must: 必须符合的子句,多个查询条件的完全匹配and
    • must_not: 不需要符合的子句,多个查询条件的相反匹配 not
    • should:至少有一个查询条件匹配,相当于or,可以有多个

      {
          "bool":{
              "must": {"match": {"tweet": "elasticseach"}},
              "must_not": {"match": {"name": "mary"}},
              "should": [
                          {"term": {"starred":true}},
                          {"term": {"unread":true}}
              ]
          }
      }
      
  • range:过滤一定范围内的数据(gt 大于,gte 大于等于, lt 小于, lte小于等于)

    range {
             field :{
                  gte: value1
                  lt:value2
             }
        }
    
  • exists,missing:查找文档中是否包含指定字段或没有某个字段,类似于SQL语句中的IS_NULL条件
  • multi_match查询:允许在做match查询的基础上同时查询多个字段,如要在tilte和body中同时检索关键字“full text search”,则可使用mutli_match检索

    {
        "multi_match":{
            "query": "full text search",
            "fields": ["title", "body"]
        }
    }
    

聚合查询 aggregations

聚合查询本想放到查询关键字中,但这部分确实会复杂很大,需要用更多的例子描述,所以这里我们单独例一个章节描述,同样以查询关键字为索引。 聚合查询和sql中的 group by 很类似,不同的是elasticseach中的聚合查询非常快,大部分查询都能在1s内完成,这对于mysql这样的传统数据库和基于MR的HIVE是不大可能实现的。

类型

  • metric 聚合查询的条件,一般是查询函数
  • buckets 聚合查询得到的结果保留到这个字段中
  • pipeline 聚合查询可以不断嵌套,深入下去

结构

聚合查询的基本结构如下,与DSL的查询结构类似,同样使用JSON结构体用于描述查询请求。

"aggregations(关键字)" : {
    "<aggregation_name(给聚合取个名称)>" : {
        "<aggregation_type(聚合类型,sum avg等等)>" : {
            <aggregation_body>
        }
        [,"meta" : {  [<meta_data_body>] } ]?
        [,"aggregations" : { [<sub_aggregation子聚合>]+ } ]?
    }
    [,"<aggregation_name_2 平行聚合>" : { ... } ]*
}

metric 聚合

metric(度量)聚合通常是常用的数学函数查询,因此我们会专挑一些有代表性的进行描述

  • sum 对某个字段求和

    {
         "aggs" : {
            "intraday_return" : { "sum" : { "field" : "change" } }
          }
    }
    
  • avg 计算所有分数的平均值,缺失值用0填充

    {
        "aggs" : {
            "avg_grade" : { "avg" : { "field" : "grade" , "missing":0} }
        }
    }
    

    返回结果为

    {
        ...
    
        "aggregations": {
            "avg_grade": {
                "value": 75
            }
        }
    }
    

通常我们需要计算一些合成的字段的平均值,此时就需要在查询体中写脚本完成,例如我们要计算两门课的平均分。

{
    "aggs" : {
        "avg_grade" : { "avg" : { "script" : "(doc['grade1'].value + doc['grade2'].value)" } }
    }
}
  • stats 常用统计查询

    {
        "aggs" : {
            "grades_stats" : { "stats" : { "field" : "grade" } }
        }
    }
    

返回结果

{
    ...

    "aggregations": {
        "grades_stats": {
            "count": 6,
            "min": 60,
            "max": 98,
            "avg": 78.5,
            "sum": 471
        }
    }
}
  • extended stats 拓展的统计查询

    {
        "aggs" : {
            "grades_stats" : { "stats" : { "field" : "grade" } }
        }
    }
    

返回结果

{
    ...

    "aggregations": {
        "grade_stats": {
           "count": 9,
           "min": 72,
           "max": 99,
           "avg": 86,
           "sum": 774,
           "sum_of_squares": 67028,
           "variance": 51.55555555555556,
           "std_deviation": 7.180219742846005,
           "std_deviation_bounds": {
            "upper": 100.36043948569201,
            "lower": 71.63956051430799
           }
        }
    }
}
  • min

    {
        "aggs" : {
            "min_price" : { "min" : { "field" : "price" } }
        }
    }
    
  • max

    {
        "aggs" : {
            "max_price" : { "max" : { "field" : "price" } }
        }
    }
    
  • percentile

  • cardinality(unique count),因为unique方法需要用到一个缓存做分布式的计算,对于海量的数据而言,如果要做到精确的unique count,缓存很容易爆掉。所以ES官方对这个值做了个限制,可以设为threshold为1000,基本上已经能保持一个比较低的错误率。 cardinality的计算使用到了算法
    HyperLogLog++

  • top hits 查询最相关的TOP N个结果

    {
        "aggs": {
            "top-tags": {
                "terms": {
                    "field": "tags",
                    "size": 3
                },
                "aggs": {
                    "top_tag_hits": {
                        "top_hits": {
                            "sort": [
                                {
                                    "last_activity_date": {
                                        "order": "desc"
                                    }
                                }
                            ],
                            "_source": {
                                "include": [
                                    "title"
                                ]
                            },
                            "size" : 1
                        }
                    }
                }
            }
        }
    }
    
  • count 计算值的总和

    {
        "aggs" : {
            "grades_count" : { "value_count" : { "field" : "grade" } }
        }
    }
    

接下来的bucket聚合会更复杂,所以我们还是单独用一个章节来讲。