ElasticSearch基础及查询语法

3,599 阅读9分钟

一、基础理论知识

  1. 介绍

    ElasticSearch 是一个近实时的搜索平台。也就是说当你索引一个文档时可能出现轻微的延迟(一般都是秒级别),公司的logcenter出现的延时是出现在Kafka2ES层,而非索引层。

    ElasticSearch 是一个分布式可扩展的实时搜索和分析引擎,一个建立在全文搜索引擎 Apache Lucene(TM) 基础上的搜索引擎。当然 ElasticSearch 并不仅仅是 Lucene 那么简单,它不仅包括了全文搜索功能,还可以进行以下工作:

    • 一个分布式的实时文档存储,每个字段都可以被索引与搜索

    • 一个分布式实时分析搜索引擎

    • 能胜任上百个服务节点的扩展,并支持 PB 级别的结构化或者非结构化数据

    ElasticSearch英文翻译:弹性搜索。

  2. 基本概念

    可以这样理解:ElasticSearch是一个面向文档型的数据库,一条数据在里面就是一个文档,用JSON作为文档序列化格式。下面是一份ElasticSearch和关系型数据库术语的对比关系表:

    MySQL

    ElasticSearch

    Database(数据库)

    对应的术语

    含义

    索引(Index)

    一系列文档的集合,类似于mysql中数据库的概念

    Table(表)

    类型(type)

    在Index里面可以定义不同的type,type的概念类似于mysql中表的概念,是一系列具有相同特征数据的结合。

    Row (行)

    文档(Document)

    文档的概念类似于mysql中的一条存储记录,并且为json格式,在Index下的不同type下,可以有许多document。

    Column (列)

    字段(Fields)

    Index (索引)

    Everything Indexed by default (所有字段默认都被索引)

    SQL (结构化查询语言)

    Query DSL (查询专用语言)

    Shards

    在数据量很大的时候,进行水平的扩展,提高搜索性能。

    分片只保存了索引中所有数据的一部分。

    我们的文档存储在分片中,并且在分片中被索引,但是我们的应用程序不会直接与它们通信,取而代之的是,直接与索引通信。

    文档存储在分片中,然后分片分配到你集群中的节点上。当你的集群扩容或缩小,Elasticsearch将会自动在你的节点间迁移分片,以使集群保持平衡。

    Replicas

    防止某个分片的数据丢失,可以并行得在备份数据里及搜索提高性能。

  3. 优势

    优势

    含义

    横向可扩展性

    增加服务器可直接配置在集群中,只需要保证cluster.name一致即可。

    分片机制

    能够提供更好的分布性,分而治之的方式来提升处理效率。

    高可用

    提供复制备份(replica)机制。

    实时性

    通过将磁盘上的文件放入文件缓存系统来提高查询速度。

    关于数据库的水平扩展和竖直扩展:对于大多数数据库而言,横向扩展意味着你的程序将做非常大的改动才能利用这些新添加的设备。对比来说,Elasticsearch天生就是分布式的,它知道如何管理节点来提供高扩展和高可用。这意味着你的程序不需要关心这些。 只要在创建集群(cluster)、节点(node)和分片(shards)的时候,按照一定的规则,则能按照你的需求进行扩展,并保证在硬件故障的时候数据依然安全。

    为说明分片和复制分片的含义,以及如何扩展,这里举一个栗子:


    (1)、启动一个空节点,这时它没有索引也没有文档数据。

    (2)、我们添加了一个名为log的索引,设置它有三个主分片。(ES默认是5个主分片)。

    (3)、单一节点运行很容易出现单点故障--数据丢失,这时我们扩展第二个节点,设置相同的cluster.name就可以加入同个集群,设置log索引每个主分片有一个复制分片,这时任意一个节点故障都能依然支持客户端的查询需求。

    (4)、这时我们继续扩展,扩展第三个节点,ES集群会重新组织自己,分片会重新被分配以达到平衡负载,这时每个节点只有两个分片,与之前相比少了一个,意味着每个节点的分片有更多的资源,比如CPU、I/O等。

    (5)、如果一个节点只有一个分片的话,那么该分片就可独享当前节点的所有资源。如果我们需要扩展到6个节点以上?主分片的数量在创建索引时已经确定,那么我们可以增加复制分片的数量,可以设置每个分片有一个复制分片为两个。

    (6)、ES可以应对单点故障,这时我们杀掉一个节点进程,且是主节点,ES会在瞬间选举出一个新的主节点,且能够支持所有数据的查询访问。

  4. 索引

    关系型数据库的B-/B+Tree,ES采用倒排索引,ES索引的一切设计都是为了提高搜索的性能。

    B-/B+Tree索引:

    是为优化写入的索引结构,特点是二叉查找效率为logN,同时插入新的节点不必移动全部节点,所以用树型结构存储索引,能同时兼顾插入和查询的性能。

    倒排索引:

    倒排索引的结构:


    举个栗子:

    ID

    Name

    Age

    Sex

    1

    Kate

    24

    2

    John

    24

    3

    Bill

    29

    那么ES建立的索引如下:

    Name:

    Term

    Posting List

    Kate

    [1]

    John

    [2]

    Bill

    [3]

    Age:

    Term

    Posting List

    24

    [1,2]

    29

    [3]

    Sex:

    Term

    Posting List

    [2,3]

    [1]

    如上,Elasticsearch分别为每个field都建立了一个倒排索引,Kate, John, 24, Female这些叫term,而1,2就是Posting List。Posting list就是一个int的数组,存储了所有符合某个term的文档id。在ES的每一部分中都采用了一些优化及压缩技术,例如Term Index采用类似字典的索引页的方式,可以理解为一棵树,Term Dictionary存储block,从Term Index找到对应的节点后再去Term Dictionary中寻找对应的block,从而磁盘去寻找Term。


    这样简化存储后,ES仍然没有满足,为了将Term Index、Term Dictionary及Posting List存储入内存,Term Index使用了FST的压缩,Posting List采用:增量编码压缩,将大数变小数,按字节存储的方式进行压缩。

    Posting List的压缩:


二、查询

和ES的交互方式取决于你是否使用JAVA。以下我们是以JAVA为例对ES的查询进行说明。

JAVA API

如果你正在使用 Java,在代码中你可以使用 ElasticSearch 内置的两个客户端:节点客户端(Node client)、传输客户端(Transport client)。Java客户端默认端口是9300,并且使用ES的原生传输协议和集群进行交互。

RESTful API with JSON over HTTP

简介

所有其他语言可以使用 RESTful API 通过端口

9200
和 ElasticSearch 进行通信。一个 ElasticSearch 请求和任何 HTTP 请求一样由若干相同的部件组成:

curl -X<VERB> '<PROTOCOL>://<HOST>:<PORT>/<PATH>?<QUERY_STRING>' -d '<BODY>'

被 < > 标记的部件

含义

VERB

适当的 HTTP

方法
谓词
: GET`、 `POST`、 `PUT`、 `HEAD 或者 `DELETE`。

PROTOCOL

http 或者 https`(如果你在 ElasticSearch 前面有一个 `https 代理)

HOST

ElasticSearch 集群中任意节点的主机名,或者用 localhost 代表本地机器上的节点。

PORT

运行 ElasticSearch HTTP 服务的端口号,默认是 9200 。

PATH

API 的终端路径(例如 _count 将返回集群中文档数量)。Path 可能包含多个组件,例如:_cluster/stats 和 _nodes/stats/jvm 。

QUERY_STRING

任意可选的查询字符串参数 (例如 pretty 将格式化地输出 JSON 返回值,使其更容易阅读)

BODY

一个 JSON 格式的请求体 (如果请求需要的话)

举两个栗子:

(1)、计算集群中文档的数量,我们可以用这个:

curl -XGET 'http://localhost:9200/_count?pretty' -d '
{
    "query": {
        "match_all": {}
    }
}

ES将返回一个HTTP状态码(例如:200 OK`)和(除`HEAD`请求)一个JSON 格式的返回值。JSON 体如下:

{
    "count" : 0,
    "_shards" : {
        "total" : 5,
        "successful" : 5,
        "failed" : 0
    }
}

(2)、以新美大日志中心的查询为例:

curl -XPOST 'http://es.data.sankuai.com/log.mapi-log-service.userbehaviours_all/_search?pretty' -d'
{
    "query": {
        //TODO:查询语句
    },
"size":"100"
}'

检索

两种方式:发送HTTP GET请求进行检索、使用ES查询表达式 (DSL) 检索。

第一种方式即构造HTTP GET请求:(以下为缩写格式,即省略了请求中所有的相同部分,例如主机名、端口号以及curl命令本身,非完整请求)

参考:www.elastic.co/guide/cn/el…

www.elastic.co/guide/cn/el…

curl -XGET /megacorp/employee/1

返回信息包含一些基本信息以及搜索的JSON元数据:

{
  "_index" :   "megacorp",
  "_type" :    "employee",
  "_id" :      "1",
  "_version" : 1,
  "found" :    true,
  "_source" :  {
      "first_name" :  "John",
      "last_name" :   "Smith",
      "age" :         25,
      "about" :       "I love to go rock climbing",
      "interests":  [ "sports", "music" ]
  }
}

第二种方式即使用使用ES查询表达式 (DSL) 检索:将请求参数按照ES约定的格式构造为一个JSON进行请求。

参考:www.elastic.co/guide/cn/el…

常用的查询:

查询方式

含义

使用方法

备注

term过滤

term主要用于精确匹配哪些值,比如数字,日期,布尔值或 not_analyzed 的字符串。

not_analyzed 的字符串:未经切词的文本数据类型。

{ 
  "query": { 
    "term": { 
      "title": "内蒙古" 
    } 
 } 
}

terms过滤

terms 跟 term 有点类似,但 terms 允许指定多个匹配条件。 如果某个字段指定了多个值,那么document需要一起去做匹配。

{
  "query": {
    "terms": {
      "title": [
        "内蒙古",
        "黑龙江"
      ]
    }
  }
}

range

range过滤允许我们按照指定范围查找一批数据。

{
"query":{
  "range": {
    "pubTime": {
      "gt": "2017-06-25",
      "lt": "2017-07-01"
    	}
  	}
	}
}

范围操作符包含:

关键字

含义

gt

大于

gte

大于等于

lt

小于

lte

小于等于

exists和missing

exists 和 missing 过滤可以用于查找文档中是否包含指定字段或没有某个字段,类似于SQL语句中的IS_NULL条件。

这两个过滤只是针对已经查出一批数据来,但是想区分出某个字段是否存在的时候使用。

{
    "exists":{
        "field":"title"
    }
}

bool过滤

bool 过滤可以用来合并多个过滤条件查询结果的布尔逻辑,它包含一下操作符:

must :: 多个查询条件的完全匹配,相当于 and。

must_not :: 多个查询条件的相反匹配,相当于 not。

should :: 至少有一个查询条件匹配, 相当于 or。

这些参数可以分别继承一个过滤条件或者一个过滤条件的数组

{
    "bool":{
        "must":{
            "term":{
                "folder":"inbox"
            }
        },
        "must_not":{
            "term":{
                "tag":"spam"
            }
        },
        "should":[
            {
                "term":{
                    "starred":true
                }
            },
            {
                "term":{
                    "unread":true
                }
            }
        ]
    }
}

三、参考

www.elastic.co/guide/en/el…

www.elastic.co/guide/cn/el…

juejin.cn/post/684490…