Elasticsearch入门

基本概念:索引、文档和RESTAPI
  • 基本概念
    索引:名词:一类相似文档的集合,类比与mysql的一张表 动词:把数据保存到es的过程
    文档:json格式,类比于mysql的一条记录,每个文档有一个Unique ID,可以自己指定也可以由es生成

  • 文档的元数据(用于标注文档的相关信息)

{
  "_index": "movies", // 文档所属的索引名
  "_type": "_doc", // 文档所属类型名,es7.0后已无意义,用_doc占位
  "_id": "1",  // 文档唯一ID
  "_score": 14.56256,  // 相关性打分
  "_version": 2,  // 文档的版本信息
  "_source": {  // 文档原始json数据
      "user_id": 9527,
      "username": "阿凯"
  }
}
  • 索引的mapping和setting
    mapping定义文档字段的类型,类比于mysql的表结构
    setting定义不同数据的分布,定义索引分布的分片信息

  • 使用场景
    es: 相关性/高性能全文检索
    关系型数据库:事务性/Join
    有时候需要把es和关系型数据库结合使用

集群、节点、分片和副本
  • 集群
    es集群是分布式的,节点结合负载均衡与数据的水平拆分

  • 节点
    节点是一个es实例(本质是一个java进程,建议生产环境一台机器只运行一个es实例,不要多个)
    data node: 保存数据的节点,当存储不够用时,可以增加data node进行扩容
    coordinating node:负责接收client的请求,分发到合适的节点并汇总结果,每个节点默认都起到coordinating node的职责
    hot&warm node:不同硬件配置的data node,实现冷热架构,降低机器成本
    machine learning node:负责跑机器学习的job,用来做异常检测
    生产环境应尽量配置单一职责的节点,通过elasticsearch.yml文件配置

  • 分片及副本

主分片:用于解决数据水平扩展,可以将数据分布到不同节点上,主分片数在索引创建时指定,后续不允许修改,除非reindex,类比于mysql的分表
副本:主分片的拷贝,用于解决高可用,即负载均衡

分片数过小,后续无法增加节点扩展,分片数过大,影响结果的相关性打分,影响准备性,单个节点分片过多也会造成资源浪费,影响性能。7.0的默认主分片是1。

文档的CURD和批量操作
  • create 创建一个文档,如果对应id的文档已存在,会报错
PUT users/_create/1  // 索引名/_create/_id
{
    "user_id": 1,
    "username": "jack"
}
  • get 获取一个文档
GET users/_doc/1  // 索引名/_type/_id
  • index 索引一个文档,如果对应id的文档不存在,则创建文档,如果已存在,则删除原文档再创建文档,版本号+1
PUT users/_doc/1  // 索引名/_type/_id
{
    "user_id": 1,
    "username": "jack"
}
  • update 更新一个文档
POST users/_update/1
{
    "doc": {
         "username": "jack"
    }
}
  • delete 删除一个文档
DELETE users/_doc/1  // 索引名/_type/_id
  • Bulk API 支持一次调用中,对不同索引进行写操作,支持index create update delete,单条失败不影响其他操作
POST _bulk
{"index": {"_index": "hb_user", "_id": 3}}
{"user_id": 2, "username": "周月"}
{"create": {"_index": "hb_user","_id": 4}}
{"user_id": 9300,"username": "夸哥","salary": 50000}
{"delete": {"_index": "hb_user","_id": 1}}
{"update": {"_index": "hb_user","_id": 4}}
{"doc": {"user_id": "9300","username": "阿夸"}}
  • mget 批量获取
GET _mget
{
  "docs": [
       {"_index": "hb_user", "_id": 3},
       {"_index": "hb_login_history", "_id": 4}
  ]
}
倒排索引

以书本为例,书的目录就是正排索引,书最后的索引的词条就是倒排索引

文档中 正排索引是文档ID到文档内容,倒排索引是文档内容中的词条到文档ID

倒排索引包含两个部分:
单词词典:记录文档中的所有单词,单词到倒排列表的对应关系
倒排列表:由倒排索引项组成:文档ID,词频,位置,偏移

例子:

单词词典

字段 倒排列表id
超人 1,2,3
蝙蝠侠 4,5

倒排列表

倒排列表id 文档ID 词频TF 位置 偏移
1 52562 1 1 <10,23>
2 542562 2 1 <11,23>
3 542562 1 1 <12,23>
4 542562 1 1 <13,23>
5 542562 1 1 <14,23>

es的json文档的每个字段都有自己的倒排索引,可以指定某些字段不做索引(优点:节省存储空间,缺点:字段无法被搜索)

通过Analyzer进行分词

Analysis - 文本分析是把全文本转换成一系列单词(term/token)的过程,也叫分词。
Analysis是通过Analyzer来实现的
除了在数据写入时转换词条,匹配Query语句时也需要用相同的分析器对查询语句进行分析

Analyzer由三部分组成:

  • Character Filter 针对原始文本进行处理,es自带的:去除html标签,字符串替换,正则匹配替换,会影响tokenizer的position和offset信息
  • Tokenizer 按照规则切分为单词
  • Token Filter 将切分的单词进行加工,小写,删除stopwords,增加同义词

ik分析器安装:
bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.1.0/elasticsearch-analysis-ik-7.1.0.zip

kibana 演示:

POST _analyze
{
  "analyzer": "ik_smart",
  "text": "中华人民共和国国歌"
}
POST _analyze
{
  "analyzer": "ik_max_word",
  "text": "中华人民共和国国歌"
}
  • ik_max_word: 会将文本做最细粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,中华人民,中华,华人,人民共和国,人民,人,民,共和国,共和,和,国国,国歌”,会穷尽各种可能的组合,适合 Term Query;

  • ik_smart: 会做最粗粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,国歌”,适合 Phrase 查询

Search API

  • URI Search : 在URI中使用查询参数
  • Request Body Search: DSL

指定查询的索引:

  • /index1/_search
  • /index1,index2/_search
  • /index*/_search

URI查询示例:

curl -XGET "http://xxxxxxxxxx/index1/_search?q=customer_first_name:Eddie"

DSL查询示例

curl -XGET "http://xxxxxxxxxx/index1/_search" -H 'Content-Type:application/json' -d'
{
  "query": {
      "match_all": {}
  }
}'

相关性指标

  • Percision(查准率):正确的内容/全部返回的结果,尽可能返回较少的无关文档
  • Recall(查全率):正确的内容/全部应该返回的结果,尽量返回较多的相关文档
  • Ranking 是否能按照相关度进行排序

es提供很多参数来改善Percision和Recall

URI Search

GET /movies/_search?q=2012&df=title&sort=year:desc&from=0&size=10&timeout=1s
{
    "profile": "true"
}
  • q指定查询语句,使用query string syntax
  • df默认字段,不指定时,会对所有字段进行查询
  • sort排序/from和size用于分页
  • profile可以查询时如何被执行的
  • 指定字段查询
GET /movies/_search?q=title:2012
GET /movies/_search?q=2012&df=title
  • 泛查询,对所有字段查询,性能不好
GET /movies/_search?q=2012
  • Term和Phrase

  • Beautiful Mind 等效于 Beautiful OR Mind

  • ”Beautiful Mind“ 等效于 Beautiful AND Mind。Phrase查询,还要求前后顺序保持一致

  • 分组和引号

title:(Beautiful Mind) 默认含义Beautiful OR Mind
title:"Beautiful Mind"等同于title:(Beautiful AND Mind)

title:(Beautiful NOT Mind)
这里分组中的OR AND NOT等同于 && || !
也可以用+ -来实现,+表示must, - 表示must not
title:(+Beautiful -Mind)

  • 范围查询, []闭区间,{}开区间
    year:{2019 TO 2018}
    year:[* TO 2018]

  • 算数符号
    year:>2010
    year:(>2010 && <=2018)
    year:(+>2010 && +<=2018)

  • 通配符查询(查询效率低,占用内存大,不建议使用。特别是放在最前面)
    ?代表1个字符,代表0或者多个字符:title:mi?d title:be

  • 正则表达
    title:[bt]oy

  • 模糊匹配与近似匹配
    title:beautifl~1
    title:"lord rings"~2

Request Body Search

一些复杂的查询只能通过DSL实现,推荐使用DSL

POST /movies/_search
{
    "_source":  ["order_date", "category.keyword"],
    "sort": [{"order_date": "desc"}],
    "from": 10,
    "size": 20,
    "query": {
        "match_all": {}
    }
}
  • 获取靠后的翻页成本较高
  • 最好在数字型与日期型的字段上排序
  • 如果_source没有存储,那就只返回匹配的文档的元数据
  • _source支持通配符,"name*"

脚本字段

GET /movies/_search
{
    "script_fields":  {
        "dollor_price": {
            "script": {
                "lang": "painless",
                "source": "doc['order_date'].value+'hello'"
            }
        }
    }
    "from": 10,
    "size": 20,
    "query": {
        "match_all": {}
    }
}

DSL实现Term Query和Phrase Query

GET /movies/_search
{
    "query": {
      "match": {
        "comment": "Last Christmas" // Last OR Christmas
      }
    }
}
GET /movies/_search
{
    "query": {
      "match": {
        "comment": {
            "query": "Last Christmas",
            "operator": "AND"
        }
      }
    }
}
GET /movies/_search
{
    "query": {
      "match_phrase": {
        "comment": {
            "query": "Last Christmas",  // 在match_phrase查询里,每个词必须是按顺序出现的
            "slop": 1
        }
      }
    }
}

query string&simple query string查询

POST users/_search
{
  "query": {
    "query_string": {
      "default_field": "name",
      "query": "Ruan AND Yiming"
    }
  }
}
POST users/_search
{
  "query": {
    "query_string": {
      "fields": ["name", "about"],
      "query": "(Ruan AND Yiming) OR (Java AND Elasticsearch)"
    }
  }
}
POST users/_search
{
  "query": {
    "simple_query_string": {
      "fields": ["name", "about"],
      "query": "Ruan Yiming",
      "default_operator": "AND"
    }
  }
}
  • simple_query_string不支持AND OR NO,会当作字符串处理,支持(+替代AND,代替OR, -代替NOT)Term之前的关系默认是OR,可以指定operator

Dynamic Mapping和常见字段类型

mapping类似数据库中的schema(表结构),作用如下:
  • 定义索引中字段的名称
  • 定义字段的数据类型,例如字符串,数字,布尔......
  • 字段,倒排索引的相关配置(Analyzed or Not Analyzed, Analyzer)
字段的数据类型
  • 简单类型:Text/Keyword Date Integer/Floating Boolean IPv4&IPv6
  • 复杂类型:对象类型/嵌套类型
  • 特殊类型(地理位置):geo_point & geo_shape / percolator

Dynamic Mapping:es根据文档信息,自动推断字段的类型,但可能不是最正确的

json类型 es类型
字符串 1. 匹配日期格式,设置为Date 2. 配置数字设置为float或者long,该选项默认关闭 3. 设置为Text,并且增加keyword子字段
布尔值 boolean
浮点数 float
整数 long
对象 object
数组 由第一个非空数值的类型所决定
空值 忽略
更改mapping的字段类型
  • 新增字段
  1. Dynamic设为true时,一旦有新增字段的文档写入,mapping也同时被更新
  2. Dynamic设为false时, mapping不会被更新,新增字段的数据无法被索引,但是信息会出现在_source中
  3. Dynamic设为strict时,文档写入失败
  • 已有字段
    一旦已经有数据写入,就不再支持修改字段定义,如果要修改,必须调用Reindex API,重建索引。
PUT /hb_user/_mapping
{
  "dynamic": false
}
GET /hb_user/_mapping

显式mapping设置和常见参数

PUT my_index
{
  "mappings": {
    "properties": {
      "first_name": {
        "type": "text",
        "copy_to": "full_name"  // 可以用full_name进行搜索,但是full_name不会出现在_source中
      },
      "last_name": {
        "type": "text",
        "copy_to": "full_name"
      },
      "mobile": {
        "type": "text",
        "index": false
      },
      "bio": {
        "type": "text",
        "index_options": "offsets"
      },
      "alias": {  // 需要对null值进行搜索,只有keyword类型支持null_value
        "type": "keyword",
        "null_value": "NULL"
      },
      "interests": {
        "type": "text"
      }
    }
  }
}

四种不同级别的Index Option配置,可以控制倒排索引记录的内容

  • docs:记录doc id
  • freqs: 记录doc id / term frequencies
  • position: 记录doc id / term frequencies/ term position
  • offsets: 记录doc id / term frequencies / term position / character offects

Text类型默认记录positions,其他默认为docs
记录内容越多,占用存储空间越大

多字段特性及Mapping中配置自定义Analyzer

多字段特性
PUT products
{
  "mappings": {
    "properties": {
      "company": {
        "type": "text",
        "fields": {
          "company_keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      },
      "comment": {
        "type": "text",
        "fields": {
          "english_comment": {
            "type": "text",
            "analyzer": "english",
            "search_analyzer": "english"
          }
        }
      }
    }
  }
}

Exact Value:无需分词,包括数字/日期/具体一个字符串,es中的keyword
Full Text:全文本,需要分词,es中的text

配置自定义Analyzer
GET _analyze
{
  "tokenizer": "whitespace",
  "filter": ["lowercase", "stop"],
  "text": ["The gilrs in China are playing this game!"]
}
PUT my_index1
{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_custom_analyzer": {
          "type": "custom",
          "char_filter": [
            "emotions"
          ],
          "tokenizer": "punctuation",
          "filter": [
            "lowercase",
            "english_stop"
          ]
        }
      },
      "char_filter": {
        "emotions":{
          "type": "mapping",
          "mappings": [
            ":) => _happy_",
            "(: => _sad_"
          ]
        }
      },
      "tokenizer":{
        "punctuation":{
          "type":"pattern",
          "pattern": "[ .,!?]"
        }
      },
      "filter":{
        "english_stop":{
          "type":"stop",
          "stopwords":"_english_"
        }
      }
    }
  }
}
GET my_index1/_analyze
{
  "analyzer": "my_custom_analyzer",
  "text": "I`m a :) person,and you?"
}

Index Template和Dynamic Template

什么是Index Template

Index Template帮你设置mappings和settings,并按照一定规则,自动匹配到新创建的索引之上

  • 修改模板不会影响已创建的索引
  • 你可以创建多个索引模板,这些设置会被”merge“在一起
  • 你可以指定”order“的数值,控制”merge“过程
PUT _template/template_default
{
  "index_patterns": ["test*"],
  "order": 0,
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 2
  },
  "mappings": {
    "date_detection": false,
    "numeric_detection": true
  }
}

当一个索引被新创建时

  • 应用es默认的settings和mappings
  • 应用order数值低的Index Template中的设定
  • 应用order数值高的Index Template中的设定,之前的设定会被覆盖
  • 应用创建索引时,用户所指定的settings和mappings,并覆盖之前的设定

查看index template

GET _template/template_default
什么是Dynamic Template

根据es识别的数据类型,结合字段名称,来动态设定字段类型,比如:

  • 所有的字符串类型都设定成keyword,或者关闭keyword字段
  • is开头的字段都设置成boolean
  • long_开头的字段都设定成long类型

目的:让es的动态字段类型推断符合你的预期

PUT test_index2
{
  "mappings": {
    "dynamic_templates":[
      {
        "full_name":{
          "path_match": "name.*",
          "path_unmatch": "*.middle",
          "mapping":{
            "type":"text",
            "copy_to":"full_name"
          }
        }
      },
      {
        "string_as_boolean": {
          "match_mapping_type": "string",
          "match": "is*",
          "mapping": {
            "type": "boolean"
          }
        }
      }
    ]
  }
}
PUT test_index2/_doc/1
{
  "name":{
    "first":"chen",
    "middle":"liang",
    "last":"hui"
  },
  "is_vip":"true"
}
GET test_index2/_search?q=full_name:(chen)

es的聚合查询简介

  • Bucket Aggregation 一些满足特定条件的文档的集合 类似sql中 group by
  • Metric Aggregation 一些数学运算,可以对文档字段进行统计分析,如sql中的 select count(*)
  • Pipeline Aggregation 对其它聚合查询进行二次聚合
  • Matrix Aggregation 支持对多个字段的操作并提供一个结果矩阵
GET hb_user/_search
{
  "size": 0,
  "aggs": {
    "gender_group": {
      "terms": {
        "field": "gender"
      },
      "aggs": {
        "avg_birth_year": {
          "avg": {
            "field": "birth_year"
          }
        },
        "max_birth_year": {
          "max": {
            "field": "birth_year"
          }
        },
        "min_birth_year": {
          "min": {
            "field": "birth_year"
          }
        },
        "birth_month_group":{
          "terms": {
            "field": "birth_month"
          }
        }
      }
    }
  }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容