ElasticSearch初体验

须要明白的问题

  1. 什么是倒排索引?它的组成是什么?node

  2. 常见的相关性算分方法有哪些?linux

  3. 为何查询语句没有返回预期的文档?git

  4. 经常使用的数据类型有哪些?Text和Keyword的区别是什么?es6

  5. 集群是如何搭建起来的?是如何实现故障转移的?github

  6. Shard具体是由什么组成的?json

Elastic Stack

构建在开源基础之上, Elastic Stack 让您可以安全可靠地获取任何来源、任何格式的数据,而且可以实时地对数据进行搜索、分析和可视化浏览器

Elasticsearch 是基于 JSON 的分布式搜索和分析引擎,专为实现水平扩展、高可用和管理便捷性而设计。安全

Kibana 可以以图表的形式呈现数据,而且具备可扩展的用户界面,供您全方位配置和管理 Elastic Stack。微信

Logstash 是动态数据收集管道,拥有可扩展的插件生态系统,可以与 Elasticsearch 产生强大的协同做用。数据结构

Beats 是轻量型采集器的平台,从边缘机器向 Logstash 和 Elasticsearch 发送数据。

基础概念

  • 文档 Document :用户存储在ES中的数据文档

  • 索引 Index :由具备一些相同字段的文档的集合

  • 类型 Type : 容许将不一样类型的文档存储在同一索引中,6.0开始官方不容许在一个index下创建多个type,统一type名称:doc

  • 节点 Node :一个Elasticsearch的运行实例,是集群的构成单元,存储部分或所有数据,并参与集群的索引和搜索功能

  • 集群 Cluster :由一个或多个节点组成的集合,共同保存全部的数据,对外提供服务(包括跨全部节点的联合索引和搜索功能等)

  • 分片 Shards :分片是为了解决存储大规模数据的问题,将数据切分分别存储到不一样的分片中

  • 副本 Replicas :副本能够在分片或节点发生故障时提升可用性,并且因为能够在全部副本上进行并行搜索,因此也能够提升集群的吞吐量

  • 近实时 Near Realtime(NRT):从索引文档到可搜索文档的时间有一点延迟(一般为一秒)

note:

  1. 在建立索引的时候若是没有配置索引Mapping,一个索引默认有5个shard和1个副本,一个索引总共有10个shard(算上副本shard)

  2. Elasticsearch 的shard其实是一个Lucene索引,截止Lucene-5843,一个Lucene索引限制的最大文档数为2,147,483,519 (= Integer.MAX_VALUE - 128)

安装Elasticsearch & Kibana

ES和Kibana的安装很简单,前提须要先安装好Java8,而后执行如下命令便可

elasticsearch单节点最简安装
# Ubuntu16.04上安装,方式有不少种,选择二进制压缩包的方式安装
# 1. 在普通用户家目录下,下载压缩包
curl -L -O https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.3.2.tar.gz
# 2. 解压
tar -xvf elasticsearch-6.3.2.tar.gz
# 3. 移动至/opt目录下
sudo mv elasticsearch-6.3.2 /opt
# 4. 修改配置文件elasticsearch.yml中的 network.host 值为 0.0.0.0,其余的配置参考官方文档
cd /opt/elasticsearch-6.3.2vi config/elasticsearch.yml
# 5. 启动单节点,而后浏览器访问host:9200便可看到ES集群信息
bin/elasticsearch


kibana最简安装
wget https://artifacts.elastic.co/downloads/kibana/kibana-6.3.2-linux-x86_64.tar.gz
shasum -a 512 kibana-6.3.2-linux-x86_64.tar.gz 
tar -xzf kibana-6.3.2-linux-x86_64.tar.gz
sudo mv kibana-6.3.2-linux-x86_64 /optcd /opt/kibana-6.3.2-linux-x86_64
# 修改 config/kibana.yml server.host: 0.0.0.0# 启动Kibana,访问 host:5601便可进入kibana界面

交互方式 Rest API

Elasticsearch集群对外提供RESTful API

  • Curl命令行

  • Kibana Devtools

  • Java API

  • 其余各类API,如Python API等

note: 咱们后面主要使用 Kibana Devtools 这种交互方式

数据类型

  • 字符串: text(分词), keyword(不分词)

  • 数值型: long, integer, byte, double, float, half_float, scaled_float

  • 布尔: boolean

  • 日期: date

  • 二进制: binary

  • 范围类型: integer_range, float_range, long_range, double_range, date_range

  • 复杂数据类型: Array, Object, Nested

  • 地理: geo_point, geo_shape

  • 专业: ip,completion, token_count, murmur3, Percolator, join

  • 组合的

探索ES集群

使用_cat API探索集群的健康状况
GET /_cat/health?v# 结果epoch      timestamp cluster       status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent1534319381 15:49:41  elasticsearch green           3         3    118  59    0    0        0             0                  -                100.0%

集群的健康状态(status)有三种:

  • green:一切正常(集群功能齐全)

  • yellow:全部数据均可用,但存在一些副本未分配(群集功能齐全)

  • red:一些数据因为某种缘由不可用(群集部分功能失效)

查看节点信息
GET /_cat/nodes?v

# 结果(个人ES集群安装了三个节点)ip            heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name10.100.97.207           30          96  13    0.15    0.08     0.08 mdi       *      master10.100.97.246           68          96   3    0.00    0.00     0.00 mdi       -      hadoop210.100.98.22            15          97   2    0.00    0.02     0.04 mdi       -      hadoop3
查看索引信息
GET /_cat/indices?v

# 结果health status index                           uuid                   pri rep docs.count docs.deleted store.size pri.store.size
green  open   logstash-2015.05.20             4BjPjpq6RhOSCNUPMsY0MQ   5   1       4750            0     46.8mb         24.5mb
green  open   logstash-2015.05.18             mDkUKHSWR0a8UeZlKzts8Q   5   1       4631            0     45.6mb         23.8mb
green  open   hockey                          g1omiazvRSOE117w_uy_wA   5   1         11            0     45.3kb         22.6kb
green  open   .kibana                         AGdo8im_TxC04ARexUxqxw   1   1        143           10    665.6kb        332.8kb
green  open   shakespeare                     5009bDa7T16f5qTeyOdTlw   5   1     111396            0     43.9mb           22mb
green  open   logstash-2015.05.19             az4Jen4nT7-J9yRYpZ0A9A   5   1       4624            0     44.7mb         23.1mb
...

操做数据

插入文档并查询
# 插入一个文档PUT /customer/_doc/1?pretty
{  "name": "John Doe"}# 结果{  "_index": "customer",  "_type": "_doc",  "_id": "1",  "_version": 1,  "result": "updated",  "_shards": {    "total": 2,    "successful": 2,    "failed": 0
  },  "_seq_no": 1,  "_primary_term": 1}# 查询该文档GET /customer/_doc/1#结果{  "_index": "customer",  "_type": "_doc",  "_id": "1",  "_version": 1,  "found": true,  "_source": {    "name": "John Doe"
  }
}

note:

  1. customer 为索引名,_doc 为type,1为文档_id,须要注意的是:在es6.x建议索引的type值固定为_doc,在以后的版本将删除type了;文档id若不指定,es会自动分配一个_id给文档

  2. 插入文档后,查看索引信息GET /_cat/indices?v能够看到多了 customer 的索引信息

  3. 文档结果,_source字段是原始的json内容,其余的为文档元数据

文档元数据

用于标注文档的元信息

  • _index: 文档所在的索引名

  • _type: 文档所在的类型名

  • _id: 文档的惟一id

  • _uid: 组合id,由_type和_id组成(6.0开始_type再也不起做用,同_id同样)

  • _source: 文档的原始json数据,能够从这里获取每一个字段的内容

  • _all: 整合全部字段内容到该字段,默认禁用

  • _routing 默认值为 _id,决定文档存储在哪一个shard上:shard_num = hash(_routing) % num_primary_shards

删除索引
DELETE customer#结果{  "acknowledged": true}GET /_cat/indices?v# 再次查看索引信息,能够发现 customer 不存在,已被删除
更新文档
PUT /customer/_doc/1?pretty{  "name": "John Doe"}

POST /customer/_doc/1/_update{  "doc": { "name": "Jane Doe" }
}

POST /customer/_doc/1/_update{  "doc": { "name": "Jane Doe", "age": 20 }
}# 能够看到 \_version的值一直在增长
删除文档
DELETE /customer/_doc/2
批量操做

es提供了_bulk API供批量操做,能够提升索引、更新、删除等操做的效率

_bulk操做的类型有四种:

  • index 索引:若已存在,则覆盖,文档不存在则建立

  • create 建立:文档不存在则异常

  • delete 删除

  • update 更新

# _bulk 任务:# 1. index建立 customer索引下id3的文档# 2. delete删除 customer索引下id3的文档# 3. create建立 customer索引下id3的文档# 4. update更新 customer索引下id3的文档POST _bulk
{"index":{"_index":"customer","_type":"_doc","_id":"3"}}
{"name":"whirly"}
{"delete":{"_index":"customer","_type":"_doc","_id":"3"}}
{"create":{"_index":"customer","_type":"_doc","_id":"3"}}
{"name":"whirly2"}
{"update":{"_index":"customer","_type":"_doc","_id":"3"}}
{"doc":{"name":"whirly3"}}

note:

  1. 批量查询用的是 Multi Get API

探索数据

一个简单的数据集,数据结构以下:

{    "account_number": 0,    "balance": 16623,    "firstname": "Bradshaw",    "lastname": "Mckenzie",    "age": 29,    "gender": "F",    "address": "244 Columbus Place",    "employer": "Euron",    "email": "bradshawmckenzie@euron.com",    "city": "Hobucken",    "state": "CO"}

导入这个简单的数据集到es中

# 下载wget https://raw.githubusercontent.com/elastic/elasticsearch/master/docs/src/test/resources/accounts.json# 导入curl -H "Content-Type: application/json" -XPOST "localhost:9200/bank/_doc/_bulk?pretty&refresh" --data-binary "@accounts.json"

上述命令是经过 _bulk API 将 account.json 的内容插入 bank 索引中,type 为 _doc

# account.json的内容:{"index":{"_id":"1"}}
{"account_number":1,"balance":39225,"firstname":"Amber","lastname":"Duke","age":32,"gender":"M","address":"880 Holmes Lane","employer":"Pyrami","email":"amberduke@pyrami.com","city":"Brogan","state":"IL"}...# 导入完成后能够看到 bank 索引已存在 1000 条数据GET bank/_search
查询数据 API

任务:查询全部数据,根据 account_number 字段升序排序

  1. URI Search 方式

GET /bank/_search?q=*&sort=account_number:asc&pretty
  1. Request Body Search 方式

GET /bank/_search
{  "query": { "match_all": {} },  "sort": [
    { "account_number": "asc" }
  ]
}

结果

{  "took": 41,  "timed_out": false,  "_shards": {    "total": 5,    "successful": 5,    "skipped": 0,    "failed": 0
  },  "hits": {    "total": 1000,    "max_score": null,    "hits": [
      {        "_index": "bank",        "_type": "account",        "_id": "0",        "_score": null,        "_source": {          "account_number": 0,          "balance": 16623,          "firstname": "Bradshaw",          "lastname": "Mckenzie",          "age": 29,          "gender": "F",          "address": "244 Columbus Place",          "employer": "Euron",          "email": "bradshawmckenzie@euron.com",          "city": "Hobucken",          "state": "CO"
        },        "sort": [          0
        ]
      }...
    ]
  }
}

各个参数意思:

  • took:本次查询耗费的时间(单位:毫秒)

  • timed_out:是否超时

  • _shards:本次查询搜索的 shard 的数量,包括成功的和失败的

  • hits:查询结果

  • hits.total:匹配的文档数量

  • hits.hits:匹配的文档,默认返回10个文档

  • hits.sort:排序的值

  • _score:文档的得分

  • hits.max_score:全部文档最高的得分

简要介绍 Query DSL

这个Elasticsearch提供的基于 json 的查询语言,咱们经过一个小任务来了解一下

任务要求:

  1. 查询 firstname 中为 "R" 开头,年龄在 20 到 30 岁之间的人物信息

  2. 限制返回的字段为 firstname,city,address,email,balance

  3. 根据年龄倒序排序,返回前十条数据

  4. 对 firstname 字段进行高亮显示

  5. 同时求全部匹配人物的 平均balance

GET bank/_search
{  "query": {    "bool": {      "must": [
        {          "match_phrase_prefix": {            "firstname": "R"
          }
        }
      ],      "filter": {        "range": {          "age": {            "gte": 20,            "lte": 30
          }
        }
      }
    }
  },  "from": 0,  "size": 10,  "sort": [
    {      "age": {        "order": "desc"
      }
    }
  ],  "_source": [    "firstname",    "city",    "address",    "email",    "balance"
  ],  "highlight": {    "fields": {      "firstname": {}
    }
  },  "aggs": {    "avg_age": {      "avg": {        "field": "balance"
      }
    }
  }
}

其中:

  • query 部分能够写各类查询条件

  • from, size 设置要返回的文档的起始序号

  • sort 设置排序规则

  • _source 设置要返回的文档的字段

  • highlight 设置高亮的字段

  • aggs 为设置聚合统计规则

更多查询示例
  • match_all 查询 bank 索引全部文档

GET /bank/_search
{  "query": {    "match_all": {}
  },  "size": 2}
  • match 全文搜索,查询 address 字段值为 mill lane 的全部文档

GET /bank/_search
{  "query": {    "match": {      "address": "mill lane"
    }
  }
}
  • match_phrase 短语匹配

GET /bank/_search
{  "query": {    "match_phrase": {      "address": "mill lane"
    }
  }
}

note: match 和 match_phrase 的区别:

  • match 中会分词,将 mill lane 拆分为 mill 和 lane, 实际查询 address 中有 mill 或者 lane 的文档

  • match_phrase:将 mill lane 做为一个总体查询,实际查询 address 中有 mill lane 的文档

  • 布尔查询(多条件查询)

GET /bank/_search
{  "query": {    "bool": {      "must": [
        { "match": { "age": "40" } }
      ],      "must_not": [
        { "match": { "state": "ID" } }
      ]
    }
  }
}
  • 布尔查询-过滤 查询 bank 索引中 balance 值在 20000 到 30000 之间的文档

GET /bank/_search
{  "query": {    "bool": {      "must": { "match_all": {} },      "filter": {        "range": {          "balance": {            "gte": 20000,            "lte": 30000
          }
        }
      }
    }
  }
}
  • 聚合查询 对全部文档进行聚合,state 值相同的分到同一个桶里,分桶结果命名为 group_by_state ,再对每一个桶里的文档的 balance 字段求平均值,结果命名为 average_balance,经过设置 size 的值为0,不返回任何文档内容

GET /bank/_search
{  "size": 0,  "aggs": {    "group_by_state": {      "terms": {        "field": "state.keyword"
      },      "aggs": {        "average_balance": {          "avg": {            "field": "balance"
          }
        }
      }
    }
  }
}

分别计算 age 值在 20~30 ,3040,4050 三个年龄段的男和女的平均存款balance

GET /bank/_search
{  "size": 0,  "aggs": {    "group_by_age": {      "range": {        "field": "age",        "ranges": [
          {            "from": 20,            "to": 30
          },
          {            "from": 30,            "to": 40
          },
          {            "from": 40,            "to": 50
          }
        ]
      },      "aggs": {        "group_by_gender": {          "terms": {            "field": "gender.keyword"
          },          "aggs": {            "average_balance": {              "avg": {                "field": "balance"
              }
            }
          }
        }
      }
    }
  }
}

更多内容请访问个人我的博客:http://laijianfeng.org

参考文档:

  1. elasticsearch 官方文档 Getting Started

  2. 慕课网 Elastic Stack从入门到实践


本文分享自微信公众号 - 小旋锋(whirlysBigData)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。

相关文章
相关标签/搜索