Elasticsearch 入门

Elasticsearch 是一个分布式的、可扩展的、近实时的开源搜索分析引擎。它支持 PB 级的容量,在存储时通过对文档的分析和建立索引,使之可以被全文搜索、分析。它的底层基于开源库 Luceue 。Elasticsearch 对 Luceue 进行了封装并提供了 REST API 的操作接口,开箱即用。

基本概念

概念对比

学习新内容时,最容易的理解方式是用它和已经熟悉的概念进行比较。下面是 Elasticsearch 与 Mysql 对应概念的比较。

概念 Mysql Elasticsearch
Index 索引 数据库 一个逻辑上存储文档的地方,可以是集群
Type 类型 数据表 一个索引可以在逻辑上分为不同的类型。与 Mysql 不同之处在于一个索引中的不同类型的字段是相同的;而数据库中不同表的字段基本上是不同的。
Document 文档 数据行 一个文档对象所有的键和值,是 JSON 格式,比 Mysql 复杂,可以包含对象、数组
Mapping 映射 数据类型 除了描述文档中每个值的数据类型,还包括字段的 index(怎样索引字符串) , analyzer(指定搜索和索引时使用的分析器)
shard 主分片 一个分片是一个 Lucene 索引。一个 ES 索引的分片数是在创建索引的时候设置的,因为有了分片,ES 水平扩展时变得容易
replica 副本分片 类似从库 ES 的副本分片可以在创建时设置,在创建后修改

一个 Elasticsearch 服务的实例为一个节点,一个节点可以包含多个分片,至少需要包含一个分片。
Elasticsearch 的存储容量大小为所有的主分片容量决定。所以在创建索引的时候需要考虑分片预分配。默认为 5 个主分片,也就是最后水平可扩展最大的容量为 5 个 ES 服务实例。

对比例子

下面是使用 Mysql 创建一个雇员数据库和使用 Elasticsearch 创建一个雇员索引的比较。
雇员属性有:first_name、last_name、age、about (简介)

使用 Mysql 创建
  1. 创建数据库 megacorp 。
  2. 创建表 employee ,定义表的字段。设置字段的长度、类型,根据需要设置表的索引。
  3. 插入数据。
使用 Elasticsearch 创建
  1. 创建索引,创建时确定索引的分片数、副本分片数。如果不指定, ES 默认 5 分片、1 副本分片。
  2. 设置索引的 Mapping 。 比如 about 用 text 类型存储,age 用 long 类型。about 需要使用 ik-analyzer 中文分词器,这样就可以通过简介的内容搜索对应的雇员;而 age 设置为 not_analyzed (建立索引的时候,直接对 age 字段值建立索引,不会对内容进行分析,基本类型默认 date、long 默认为 not_analyzed)。
  3. 索引雇员文档到 Elasticsearch 中。

默认情况下,文档中每一个属性都会被索引,没有索引的属性是不能被搜索的。

Elasticsearch 集群搭建

使用 Docker-compose 可以让搭建 Elasticsearch 变得更简单。
集群文件目录如下:


Docker-compose 目录结构.png

docker-compose.yml 文档内容

version: '2.2'
services:
  elasticsearch:
    image: elasticsearch:6.5.1
    container_name: es
    environment:
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - ./es1/data:/usr/share/elasticsearch/data
      - ./es1/es.yml:/usr/share/elasticsearch/config/elasticsearch.yml
    ports:
      - 9200:9200
      - 9300:9300
    networks:
      - esnet
  elasticsearch2:
    image: elasticsearch:6.5.1
    container_name: es2
    environment:
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - ./es2/data:/usr/share/elasticsearch/data
      - ./es2/es.yml:/usr/share/elasticsearch/config/elasticsearch.yml
    networks:
      - esnet
  elasticsearch3:
    image: elasticsearch:6.5.1
    container_name: es3
    environment:
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - ./es3/data:/usr/share/elasticsearch/data
      - ./es3/es.yml:/usr/share/elasticsearch/config/elasticsearch.yml
    networks:
      - esnet

networks:
  esnet:

ES_JAVA_OPTS 设置 ES 使用的最大与最小 heap 空间。
主节点 es.yml

cluster.name: es-cluster
bootstrap.memory_lock: true
node.name: node-master
node.master: true
node.data: true

network.host: 0.0.0.0
http.port: 9200
transport.tcp.port: 9300
network.publish_host: es
transport.tcp.compress: true
discovery.zen.ping.unicast.hosts: ["es:9300", "es1:9300", "es3:9300"]

cluster.name 为 ES 集群名称,集群所有的节点必须是相同的名称。
bootstrap.memory_lock 用于锁定 ES 进程使用的内存地址,防止被 swap out
node.name 为节点的名称
node.master 是否为主节点
node.data 节点是否存储数据
http.port 为外部访问 ES 服务的端口
transport.tcp.port 为 ES 集群通信的端口
transport.tcp.compress 集群通信时进行压缩
discovery.zen.ping.unicast.hosts 单播发现。 ES 将在这里面的地址去通信发现集群节点
工作节点 es.yml

cluster.name: es-cluster
bootstrap.memory_lock: true
node.name: node-master-3
node.master: false
node.data: true

network.host: 0.0.0.0
http.port: 9200
transport.tcp.port: 9300
network.publish_host: es3
discovery.zen.ping.unicast.hosts: ["es:9300", "es2:9300", "es3:9300"]

工作节点与主节点主要是 node.master 的配置不同

docker-compose up

这样一个主节点、2个工作节点的 Elasticsearch 集群就搭建起来了。

结构化搜索实践

一个 Elasticsearch 的查询包含:

  1. 查询内容所在的索引、类型。 多个索引、多个类型之间使用“,”分割。
  2. 路由 routing 。如果数据建立索引的时候有指定路由,查询的时候可以指定路由,这样 ES 就不用到每个分片去查询一次了。
  3. 查询语句 query 。
  4. 排序。根据指定字段、排序方式进行排序。
  5. 分页。可以通过 from、limit 查询指定的数据。
    一个简单的 DSL SQL
curl -X GET "localhost:9200/bank/account/_search" -d '
{
    "query" : {
        "match": {
            "title" : "search"
        }
    },
    "from": 10,
    "size": 10,
    "sort": [
        {"date": {"order":"asc"}}
    ]
}'

bank 为查询的索引; account 为查询的类型;query 中为查询语句。

Elasticsearch 中的查询分为简单查询、组合查询。
常用的简单查询又分为了查询(query context)、过滤(filter context)。查询时不仅要找到匹配对应内容的文档,还会计算文档的分数(score), 过滤只需找到对应的文档,而不计算文档的分数。官方推荐能用过滤的地方就不要用查询。

简单查询
  1. match_all 和 match_none
    查询所有的内容
curl -X GET "localhost:9200/bank/_search" -d '
{
    "query" : {
        "match_all": {}
    }
}'
  1. 全文索引
    a. match 指定的分析器先对查询内容进行分析,然后对分析的内容在倒排索引中进行查询; match_phrase 也会先将搜索内容分析为词项,然后对词项进行搜索,但是匹配的数据需要包含所有的词项。
curl -X GET "localhost:9200/bank/account/_search" -d '
{
    "query" : {
        "match": {"title":"search"}
    }
}'

b. multi_match 通过对多个字段进行 match 搜索

curl -X GET "localhost:9200/bank/_search" -d '
{
    "query" : {
        "multi_match": {
            "query":"this is test",
            "fields": ["title", "subtitle"]
        }
    }
}'

c. query_string 通过查询语句进行查询
new york city 和 big apple 是两个独立的查询内容

curl -X GET "localhost:9200/bank/_search" -d '
{
    "query" : {
        "query_string": {
            "query":"(new york city) OR (big apple)",
            "default_field": ["subtitle"]
        }
    }
}'
  1. Term 查询
    全文查询在查询前会将查询内容分析为词项,然后进行查询; term 查询不对查询内容进行分析,是对值进行精确的查询。Term 查询不会计算查询结果的分数(score),属于过滤查询(filter context)。
    a. term 和 terms
    对指定的一个和多个内容进行精确查询
curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
    "query": {
        "terms" : { "user" : ["kimchy", "elasticsearch"]}
    }
}
'

b. range 查询
文档属性值在一个范围的查询。可以是字符串、数字、日期。

curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
    "query": {
        "range" : {
            "age" : {
                "gte" : 10,
                "lte" : 20
            }
        }
    }
}'

c. exists 查询
查找指定属性至少又一个非空值的文档。

curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
    "query": {
        "exists" : { "field" : "user" }
    }
}'

d. wildcard 查询
根据通配符进行查询(? 匹配1个任意字符;* 匹配多个任意字符)。查询会耗性能。

curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
    "query": {
        "wildcard" : { "user" : "ki*y" }
    }
}'

复合查询

将多个简单查询通过组合起来就是一个复合查询了。常用的组合方式有下面几种。

  1. constant_score。这个查询里面的查询将不再计算分数,统一返回指定的分数。
curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
    "query": {
        "constant_score" : {
            "filter" : {
                "term" : { "user" : "kimchy"}
            },
            "boost" : 2
        }
    }
}'

查询结果所有文档的 _score 都为 2 。

  1. bool
    逻辑组合,包括 must、should、must_not、filter。must 和 should 的查询会计算分数,其他的不会。
    must 必须包含; should 单独查询的时候,至少需要满足一个条件,与 must、filter 组合的时候可以不需要满足。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,137评论 6 511
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,824评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,465评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,131评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,140评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,895评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,535评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,435评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,952评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,081评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,210评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,896评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,552评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,089评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,198评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,531评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,209评论 2 357

推荐阅读更多精彩内容