ElasticSearch快速指南

ElasticSearch是基于Apache Lucene的分布式搜索引擎, 提供面向文档的搜索服务。

安装ElasticSearch

可以在官网下载压缩包, 在解压目录中执行bin/elasticsearch来启动服务, 或者使用包管理器来安装启动.

ES默认端口为9200, 本地启动ES后向http://localhost:9200发送GET请求可以查看ES的基本信息:

GET 'localhost:9200'
{
"name" : "hiTUe19",
"cluster_name" : "elasticsearch_finley",
"cluster_uuid" : "cfKnyFL1Rx6URmrmAuMBFw",
"version" : {
"number" : "5.1.2",
"build_hash" : "c8c4c16",
"build_date" : "2017-01-11T20:18:39.146Z",
"build_snapshot" : false,
"lucene_version" : "6.3.0"
},
"tagline" : "You Know, for Search"
}

文档

ElasticSearch采用三层数据结构来管理数据:

  • 索引(index): 索引是最高层的数据结构,可以定义独立的搜索索引和分片存储策略
  • 类型(type): 每个index可以拥有多个type, 用于存储不同类型的文档
  • 文档:文档是最基本的数据结构,存储和搜索都是围绕文档展开的

ElasticSearch中的文档是一个Json对象,搜索的结果是文档的集合因此被称为面向文档的搜索。

与三层数据结构相对应,我们可以使用三个字段来唯一标识文档:

  • _index: 代表文档所在的索引。索引名必须小写, 不能以下划线开头, 不能包含逗号.
  • _type: 代表文档所在的类型集。type名可以为大小写, 不能以下划线开头, 不能包含逗号.
  • _id: 用于唯一标识某个type中的文档

创建文档

IndexAPI可以用于创建文档:

$ POST 'localhost:9200/blog/user/'
content-type: application/json
body:
{
"id": 1,
"nickname": "finley"
}
response:
{
"_index": "blog",
"_type": "user",
"_id": "AV5WoO0MdsHuOObNBTWU",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"created": true
}

使用POST请求创建文档, 在url中指定_index_type, 在请求体中使用json格式提交文档数据。

_index_type不存在ES会自动创建。上述请求中文档的_id字段由ElasticSearch创建,我们也可以自己指定_id:

POST localhost:9200/blog/user/2/
content-type: application/json
{
"id": 2,
"nickname": "easy"
} response:
{
"_index": "blog",
"_type": "user",
"_id": "2",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"created": true
}

访问文档

使用GET请求访问文档,需要提供_index_type_id三个参数唯一标识文档。

GET localhost:9200/blog/user/2/
response:
{
"_index": "blog",
"_type": "user",
"_id": "2",
"_version": 2,
"found": true,
"_source": {
"id": 2,
"nickname": "easy"
}
}

更新文档

因为修改文档后难以更新索引,因此ElasticSearch修改文档的操作是通过删除原文档后重新添加新文档来进行的。

使用IndexAPI对已存在的文档发送POST请求则会更新文档:

POST localhost:9200/blog/user/2/
content-type: application/json
{
"nickname": "easy",
"gender": "male"
} response:
{
"_index": "blog",
"_type": "user",
"_id": "2",
"_version": 2,
"result": "updated",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"created": false
}

注意_versioncreatedresult字段显示文档已被更新。通过GET请求查看更新后的文档:

GET localhost:9200/blog/user/2/
{
"_index": "blog",
"_type": "user",
"_id": "2",
"_version": 2,
"found": true,
"_source": {
"nickname": "easy2",
"gender": ”male“
}
}

注意到原文档中的_id字段已经不见了,文档完全由我们发送的上一个POST请求定义。

修改文档也可以通过PUT方法:

PUT localhost:9200/blog/user/2/
content-type: application/json
{
"id": 2,
"nickname": "easy3"
} {
"_index": "blog",
"_type": "user",
"_id": "2",
"_version": 3,
"result": "updated",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"created": false
}

再次通过GET请求确认文档已被修改:

GET localhost:9200/blog/user/2/
{
"_index": "blog",
"_type": "user",
"_id": "2",
"_version": 3,
"found": true,
"_source": {
"id": 2
"nickname": "easy3",
}
}

删除文档

删除文档需要发送DELETE请求:

DELETE localhost:9200/blog/user/2/
response:
{
"found": true,
"_index": "blog",
"_type": "user",
"_id": "2",
"_version": 4,
"result": "deleted",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
}
}

索引

ElasticSearch中的Index是最高级的逻辑的结构, 类似于MySQL中的数据库(schema),可以配置独立的搜索策略和存储策略。

ElasticSearch通过倒排索引进行搜索,所谓倒排索引是指对文档进行分析提取关键词,然后建立关键词到文档的索引,当我们搜索关键词时就可以找到它所关联的文档。

我们可以通过在Index中配置分析器和映射来设置倒排索引的策略。

分析器是通用的从文档提取关键词的方法,即将文档中某个字段映射为关键字的方法。例如:过滤停用词,分词, 添加同义词等。

映射则是具体指定文档中的某个字段应该使用什么分析器来提取关键词。

分析器

这个拆分的过程即是分析的过程, 分析执行的操作包括不限于: 字符过滤, 分词, 停用词过滤, 添加同义词.

ES提供了很多内置分析器:

  • standard: 默认分析器, 根据Unicode定义删除标点并将词条小写
  • simple: 根据空格分词并将词条小写
  • whitespace: 根据空格分词但不将词条小写
  • english: 过滤英文停用词并将词条还原为词根, 详情参考官方文档.
  • ngram: 滑动窗口分析器,取文本中所有子串作为关键词。 比如对easy进行处理可以得到关键词:easyeaassyeasasyeasy
  • edge-ngram: 边缘固定滑动窗口分析器,取文本所有从头开始的子串作为关键词。 比如对easy进行处理可以得到关键词:eeaeaseasy。常用于联想搜索,根据用户输入前几个字符进行搜索。

此外, 也可以通过配置字符过滤器(char_filter), 词过滤器(filter), 分词器(tokenizer)的方式来自定义分析器。

这里展示基于ngram的分析器定义:

PUT /blog
{
"settings": {
"analysis": {
"filter": {
"grams_filter": {
"type": "ngram",
"min_gram": 1,
"max_gram": 5
}
},
"analyzer": {
"gram_analyzer": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"lowercase",
"grams_filter"
]
}
}
}
}
},
mappings: {...}
}

自定义分析器的更多信息可以查阅官方文档:

若需要中文支持, 则可以使用插件elastic-analysis-ik

类型和映射

映射则是具体指定文档中的某个字段应该使用什么分析器来提取关键词:

PUT /blog
{
"settings": { ... },
"mappings": {
"user": {
"properties": {
"nickname": {
"type": "string",
"analyzer": "gram_analyzer",
"fields": {
"keyword:": {
"type": "keyword"
}
}
},
"status": {
"type": "text",
"fields": {
"keyword:": {
"type": "keyword"
}
}
}
}
}
}
}

上述JSON中user项定义了一个根对象, 它通常与文档对应。根对象下可以包含下列几个字段:

文档中每一个字段都有3个配置项:

  • type: 指定字段类型, 如:textlongdoubledate.
  • index: 指定字段索引的类型:
  • no: 不可被搜索
  • not_analyzed: 必须精确匹配
  • analyzed: 使用分析器建立倒排索引
  • analyzer: 该字段使用的默认分析器
  • fields: 字段的属性, 可以配置独立的type, index和analyzer。用于将一个字段映射为不同类型适应不同用途。

管理索引

在分析器及映射两节中展示了创建索引所需的PUT请求片段,将类型和映射一节中PUT请求的settings字段, 用分析器一节中的settings字段替换即可得到完整创建索引请求。

发送DELETE请求可以删除索引:

  • DELETE /user: 删除user索引
  • DELET /user1,user2: 删除user1和user2两个suoyin
  • DELETE /user*: 根据通配符删除索引
  • DELET /_allDELETE /*: 删除所有索引

GET /_cat/indices可以列出ElasticSearch上的所有索引。

GET /blog?pretty列出索引blog的所有信息。

查询

虽然ES提供了简易搜索API但在应用中我们通常更多地使用结构化搜索.

结构化搜索将查询条件以json的形式包含在http请求的body中,通常情况下搜索请求应该使用GET方法但不是所有的客户端和服务端都支持GET请求包含body。 因此,ElasticSearch支持使用GET或POST进行搜索。

# 列出所有文档
GET /_search
# 列出索引blog下的所有文档
GET /blog/_search
# 列出类型/blog/user下的所有文档
GET /blog/user/_search

基本查询

term查询

term查询类似于SQL中的=

POST /blog/user/_search
{
"query": {
"term": {
"nickname": "eas"
}
}
} response:
{
"took": 23,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 2,
"max_score": 0.45532417,
"hits": [
{
"_index": "blog",
"_type": "user",
"_id": "1",
"_score": 0.45532417,
"_source": {
"nickname": "easy",
"status": "normal"
}
},
{
"_index": "blog",
"_type": "user",
"_id": "2",
"_score": 0.43648314,
"_source": {
"nickname": "ease",
"status": "normal"
}
}
]
}
}

根据我们上文配置的gram_analyzer分析器, 关键词eas会匹配到easyease两个文档。

在响应的hits.hits字段中我们可以看到匹配的文档,文档_score字段是采用TF-IDF算法得出匹配程度得分,结果集中的文档按照得分降序排列。

terms查询

terms查询可以视为多个term查询的组合:

POST /blog/user/_search
{
"query": {
"terms": {
"nickname": ["easy", "ease"]
}
}
} response:
{
"took": 18,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 2,
"max_score": 1.0970675,
"hits": [
{
"_index": "blog",
"_type": "user",
"_id": "2",
"_score": 1.5779335,
"_source": {
"nickname": "ease",
"status": "normal"
}
},
{
"_index": "blog",
"_type": "user",
"_id": "4",
"_score": 1.0970675,
"_source": {
"nickname": "easy",
"content": "simple",
"status": "normal"
}
}
]
}
}

match查询

很多情况下用户可能输入多个关键词进行查询, match查询会将用户输入的内容分词生成多个term查询进行处理:

POST /blog/user/_search
{
"query": {
"match": {
"nickname": "eas sim"
}
}
} response:
{
"took": 19,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 3,
"max_score": 1.1382749,
"hits": [
{
"_index": "blog",
"_type": "user",
"_id": "3",
"_score": 1.1382749,
"_source": {
"nickname": "simple",
"status": "normal"
}
},
{
"_index": "blog",
"_type": "user",
"_id": "2",
"_score": 1.0548241,
"_source": {
"nickname": "ease",
"status": "normal"
}
},
{
"_index": "blog",
"_type": "user",
"_id": "1",
"_score": 1.049597,
"_source": {
"nickname": "easy",
"status": "normal"
}
}
]
}
}

若以eas sim为关键词进行term查询不会匹配到任何文档。

组合查询

bool查询

Bool查询用于组合多个条件查询相关度最高的文档, 下面展示了一个Bool查询请求:

POST /user/naive/_search
{
"query": {
"bool": {
"must": {
"match": {
"nickname": "easy"
}
},
"must_not": {
"match": {
"nickname": "hard"
}
},
"should": {
"match": {
"nickname": "simple"
}
},
"filter": [
{
"term": {
"status": "normal"
}
}
]
}
}
} response:
{
"took": 20,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 3,
"max_score": 1.3847495,
"hits": [
{
"_index": "blog",
"_type": "user",
"_id": "4",
"_score": 1.3847495,
"_source": {
"nickname": "easy",
"content": "simple",
"status": "normal"
}
},
{
"_index": "blog",
"_type": "user",
"_id": "5",
"_score": 0.45532417,
"_source": {
"nickname": "easy",
"content": "bitter",
"status": "normal"
}
}
]
}
}

上述bool查询的目标为:

  • must条件必须满足, 即nickname字段必须与词条easy匹配,字段的匹配程度会影响得分
  • must_not条件必须不满足, 即nickname字段不能与词条hard匹配
  • should条件不做要求, 但满足should条件的文档会获得更高的相关度评分_score。 当should查询中包含多个字段时, 会将各字段得分的和作为总分。所以查询到两个nickname与easy匹配的文档,但是contentsimple的字段获得了更高的评分。
  • filter条件必须满足,但是匹配程度不会影响得分。

dismax查询

上文已经提到bool查询的should查询会将各字段得分之和作为总分,然而在实际应用中通常一个字段高度匹配的文档可能比拥有多个字段低匹配更符合用户的期望。

dismax查询同样用于组合多个查询,但是按照匹配程度最高的字段确定总分:

{
"query": {
"dis_max": {
"queries": [
{
"match": {
"nickname": "easy"
}
},
{
"match": {
"content": "easy"
}
}
]
}
}
}

排序

ElasticSearch的搜索结果默认按照_score进行降序排列,在一些情况下我们希望自定义排序方式, 比如按创建时间排列。

POST /blog/user/_search
{
"query" : {
"bool" : {
"filter" : { "term" : { "uid" : 1 }}
}
},
"sort": { "date": { "order": "desc" }}
}

我们甚至可以使用ElasticSearch提供的painless脚本语言编写一个复杂的排序函数:

POST /blog/user/_search
{
"query" : {
"bool" : {
"filter" : { "term" : { "uid" : 1 }}
}
},
"sort": {
"_script": {
"type": "number",
"script": {
"inline": "doc['followerNum'].value * Math.sqrt(1.0 / (0.01 + Math.pow(params.now - doc['createTime'].value, 2))",
"lang": "painless",
"params": {
"now": 1517128545269
}
},
"order": "desc"
}
}
}

聚合

聚合用于分析查询结果集的统计指标, ElasticSearch引入了两个相关概念:

  • 桶(Buckets): 结果集中满足特定条件的文档的集合
  • 指标(Metrics): 桶中文档的统计值,如所有文档特定字段的平均值
POST /car/_search
{
"size" : 0,
"aggs": {
"colors": {
"terms": {
"field": "color"
},
"aggs": {
"avg_price": {
"avg": {
"field": "price"
}
}
}
}
}
} response:
{
"took": 81,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 7,
"max_score": 0,
"hits": []
},
"aggregations": {
"colors": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "red",
"doc_count": 4,
"avg_price": {
"value": 32500
}
},
{
"key": "green",
"doc_count": 2,
"avg_price": {
"value": 21000
}
},
{
"key": "blue",
"doc_count": 1,
"avg_price": {
"value": 15000
}
}
]
}
}
}

我们统计了不同颜色车辆的平均价格,因为设置了size=0所以不会有任何hits返回。

ElasticSearch指南的更多相关文章

  1. Loggly:提高ElasticSearch性能的九个高级配置技巧

    Loggly日志管理服务在其很多核心功能里使用ElasticSearch作为搜索引擎.Jon Gifford在其文章“ElasticSearch vs Solr”中指出,日志管理领域对搜索技术有了更高 ...

  2. ElasticSearch 常用查询语句

    为了演示不同类型的 ElasticSearch 的查询,我们将使用书文档信息的集合(有以下字段:title(标题), authors(作者), summary(摘要), publish_date(发布 ...

  3. 常用ElasticSearch 查询语句

    为了演示不同类型的 ElasticSearch 的查询,我们将使用书文档信息的集合(有以下字段:title(标题), authors(作者), summary(摘要), publish_date(发布 ...

  4. ElasticSearch 7.X版本19个常用的查询语句

    整理一篇常用的CRUD查询语句,之前这篇文件是在17年左右发表的,从英文翻译过来,现在采用7.x 版本进行实验,弃用的功能或者参数,我这边会进行更新,一起来学习吧. 为了演示不同类型的 Elastic ...

  5. 常用的Elasticseaerch检索技巧汇总

    本篇博客是对前期工作中遇到ES坑的一些小结,顺手记录下,方便日后查阅. 0.前言 为了讲解不同类型ES检索,我们将要对包含以下类型的文档集合进行检索: . title 标题: . authors 作者 ...

  6. 日志分析工具ELK(五)

    八.Kibana实践 选择绝对时间和相对时间 搜索 还可以添加相关信息 自动刷新页面时间,也可以关闭 创建图像,可视化 编辑Markdown,创建一个值班联系表 值班联系表 保存 再创建一个饼图;查看 ...

  7. Elasticsearch 权威指南

    Elasticsearch 权威指南 http://fuxiaopang.gitbooks.io/learnelasticsearch/content/index.html

  8. Elasticsearch 权威指南 NESTAPI地址

    Elasticsearch 权威指南:http://fuxiaopang.gitbooks.io/learnelasticsearch/content/index.html NEST:http://n ...

  9. 史上最全面的Elasticsearch使用指南

    Elasticsearch使用指南 Elasticsearch使用指南 前言 ES是什么 什么是全文检索 ES的应用场景 ES的存储结构 第一章:安装 1.下载 2.解压 3.配置 4.启动 5.查看 ...

随机推荐

  1. Codeforces434D 网络流

    思路: 题意:有n<=50个点,每个点有xi有[li, ri]种取值,-100 <= li <= ri <= 100,并且给定m<=100条边,每条边为u,v,d表示xu ...

  2. Oracle 建表

    -- Create table create table STUDENT ( sno ) not null, sname ) not null, ssex ) not null, sbirthday ...

  3. vuejs v-model

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  4. JDOJ 2939: Suffix Automaton 广义后缀自动机_统计子串

    建立广义后缀自动机,对每个节点都建立各自的 $Parent$ 数组. 这样方便统计,不会出现统计错误. 考虑新加入一个字符. 1 这条转移边已经存在,显然对答案没有贡献. 2 这条转移边不存在,贡献即 ...

  5. 【转】CentOS下firefox安装flash说明

    http://www.cnblogs.com/lamper/archive/2013/01/16/2862254.htm CentOS下自带了firefox,但没有flash插件的,按它自己的提示安装 ...

  6. maven中使用mybatis

    1.Mybatis优缺点 优点: Mybatis实现了对Dao层的封装,隔离了SQL语句,便于管理,避免了像JDBC那样操作数据集,便于扩展等等. 缺点: Mybatis属于?半自动“ORM”,比Hi ...

  7. 參加北京bluemix云计算大会偶记

    我就不写散文了.博客也要轻量化. 记录心路历程吧. 这是一次ibm的技术大会.也是传道大会,洗脑大会.会议主题看起来非常多,占领了北京国际饭店的三层,作为一个老ibm bp感受非常多. 1.北京的创业 ...

  8. iOS 7 UI 过渡指南 - 支持续 iOS 6(iOS 7 UI Transition Guide - Supporting iOS 6)

    iOS 7 UI Transition Guide Preparing for Transition Before You Start Scoping the Project Supporting i ...

  9. 分享一下js正则中惰性与贪婪

    首先引入一个介绍比较详细的网站 http://www.cnblogs.com/yuaima/p/5258513.html http://www.jb51.net/article/31491.htm 接 ...

  10. Installation from source on Windows 7 with Visual C++2012

    在这部分说明里,你将会学习到在配备有Visual C++的Windows平台下从源码安装ViSP.下面的这些安装步骤已经在32位Windows系统,CMake3.1和Visual Studio 201 ...