Elasticsearch 深入学习
< 返回列表时间: 2019-10-25来源:OSCHINA
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
es 与mysql


es 用途 与 索引构建
1. es 用于检索
当 es 用于 搜索的时候,那么就需要将 对应的 目标属性 写在一个 索引的 字段里面进行对应。
比如 搜索 对应的房屋。 那么 构建 es 的房屋索引的时候, 就需要 将 数据库房屋表id , 房屋名称, 房屋 描述 等等 其他属性可能
用到的 检索条件和属性 构建在 es 的房屋 索引里面。
当用户搜索比如 房屋名称的时候, 就会先用房屋名称去 es 里面去搜索 相关数据, 返回 房屋 id ,房屋名称 等其他属性,
之后 就可以 根据 房屋id 和其他数据再去 查询 mysql 拿到 对应的更多,更真实的 房屋数据给用户了。
也就是 真实数据 在mysql 里面, 查询的时候,从es 取到 相关的数据,这时候可以直接返回给用户,也可以根据es数据再次去mysql 里面获取。
es的索引数据,可以使用定时器去定时 从mysql 里面 取,或者 将 新增 改动的数据放入 mq里面,之后异步写入 es 中。

2. es 用于 数据分析, 数据报表
目前 公司就在 用es 做这块工作。
因为有数据分析,与数据报表,因此 建立 es 索引就有 对应的 指标(新增客户数 等 报表字段),维度(时间,组织等查询条件) 的字段属性要求了。
使用定时器或者其他方式 从mysql 中 取基础数据,或者 将mysql 的数据汇总之后 存入 es 里面,
查询报表或者数据分析 展示数据的时候,就直接从 es 里面取数展示了,或者将 es 中的数据 聚合 之后再展示。
这种用途,es 的聚合 查询就会用得比较多。

es 数据建模




mapping




一般 date_detection 设置为 false ,手动指定日期类型


何种类型


是否需要检索




实例



以上的意思是 因为 content 内容太多了,如果 每次查询
都取出来 content 那么性能太差了。 所有这样可以优化性能效率。
同时 不将 content 内容放入 _source 里面 .

关联关系处理


例子

也就是将 博客的 评论内容 也放入 blog 索引的内容里面。
查询






即将 type 设置 为 nested 即可



关联关系处理之Parent/Child




管理


防止字段过多







聚合分析 以下实例 数据 # aggregation POST test_search_index/doc/_bulk {"index":{"_id":"1"}} {"username":"alfred way","job":"java engineer","age":18,"birth":"1990-01-02","isMarried":false,"salary":10000} {"index":{"_id":"2"}} {"username":"tom","job":"java senior engineer","age":28,"birth":"1980-05-07","isMarried":true,"salary":30000} {"index":{"_id":"3"}} {"username":"lee","job":"ruby engineer","age":22,"birth":"1985-08-07","isMarried":false,"salary":15000} {"index":{"_id":"4"}} {"username":"Nick","job":"web engineer","age":23,"birth":"1989-08-07","isMarried":false,"salary":8000} {"index":{"_id":"5"}} {"username":"Niko","job":"web engineer","age":18,"birth":"1994-08-07","isMarried":false,"salary":5000} {"index":{"_id":"6"}} {"username":"Michell","job":"ruby engineer","age":26,"birth":"1987-08-07","isMarried":false,"salary":12000}




聚合分析-分类

metric

cardinality 就是 计算数目的 类似于 sql 里面的 distinc count(*)
percentile 就是百分位数的统计
top hits 取 前几个数
min

cardinality

extended stats

Percentile


比如 第一个 1.0 : 5150 也就是 百分之1 的数值 范围是 5150 以内
5% 的数值在 5750 之内 指定 百分比的对应的数值: 以下返回 百分比占比 95%, 99%, 99.9% 对应的数值范围 GET test_search_index/_search { "size": 0, "aggs": { "per_age": { "percentiles": { "field": "salary", "percents": [ 95, 99, 99.9 ] } } } }



Percentile Rank 百分位排名

以上 就是 求出 工资 为 11000 和 30000 在 数据里面的 占比 百分位数
结果是 11000 为 50% , 30000 为 75%
Top Hits

以上是 按照 job.keyword 分组,且取分组是 10个分组数据,
之后 每个分组 按照 年龄倒序取前10个详情数据返回
也就是 分组之后,再获取每个组里面的详情数据就可以 使用这个
Bucket


Terms

range

Date Range


Historgram


效果图


以上例子可以看出, 比如 有 5000 ,和 8000 的 那么都归属于 5000的分组。
10000 和 12000 归属于 1W分组。
范围分组是 [0,5000], [5000,10000], [10000,15000] ...
这样的
extended_bounds 可以补全


Date Historgram

效果图



Bucket + Metric 聚合分析

也就是分桶之后再分桶


效果图: 千层饼




Pipeline 聚合分析



Min bucket
实例 GET test_search_index/_search { "size":0, "aggs":{ "jobs":{ "terms": { "field": "job.keyword", "size": 10 }, "aggs":{ "avg_salary":{ "avg": { "field": "salary" } } } }, "min_salary_by_job":{ "min_bucket": { "buckets_path": "jobs>avg_salary" } } } }







Derivative

导数: 即看一个数的 发展趋势
Moving Average 移动平均值

移动平均值: 数据变化的趋势

作用范围

filter

注意 aggs 加上 filter 还得 额外加上 一个 aggs

也就是 jobs_salary_small 的聚合 不影响 同级的 jobs 的 聚合
post-filter

即聚合分析还是针多所有 文档, post_filter 只显示 满足条件的数据
当然也可以加上 query 语句 。
适合于 整体聚合数据与 返回部分数据
global


聚合排序

不指定 order 默认按照 doc_count 倒排

先分桶,然后按照 平均值进行 排序桶

多值


原理与精准度问题
min



terms 不准确

正常应该是 abc 的




上例中:
doc_count_error_upper_bound= 4 +2
即 node1 出来的最后一个 d(4) + node2 最后的 b(2)
因为剩下的 c(3) 与 d(1) 不可能超过 6
sum_other_doc_count = 相比总的 文档,漏了c 即 c(3+3) = 6
了解即可, 没有参考意义

比如

因为 node2 中没有 d ,所以去最新值 b(2) 即 doc_count_eror_upper_bound 为2

也就是 不指定 term 的 size ,全部返还即可,也可以避免这个问题
近似统计算法

聚合例子 # aggregation POST test_search_index/doc/_bulk {"index":{"_id":"1"}} {"username":"alfred way","job":"java engineer","age":18,"birth":"1990-01-02","isMarried":false,"salary":10000} {"index":{"_id":"2"}} {"username":"tom","job":"java senior engineer","age":28,"birth":"1980-05-07","isMarried":true,"salary":30000} {"index":{"_id":"3"}} {"username":"lee","job":"ruby engineer","age":22,"birth":"1985-08-07","isMarried":false,"salary":15000} {"index":{"_id":"4"}} {"username":"Nick","job":"web engineer","age":23,"birth":"1989-08-07","isMarried":false,"salary":8000} {"index":{"_id":"5"}} {"username":"Niko","job":"web engineer","age":18,"birth":"1994-08-07","isMarried":false,"salary":5000} {"index":{"_id":"6"}} {"username":"Michell","job":"ruby engineer","age":26,"birth":"1987-08-07","isMarried":false,"salary":12000} GET test_search_index/_search GET _cat/indices GET test_search_index/_search { "size":1, "from":2, "aggs": { "people_per_job": { "terms": { "field": "job.keyword" } } } } GET test_search_index/_search { "size":0, "aggs": { "people_per_job": { "terms": { "field": "job.keyword" } }, "avg_salary":{ "avg": { "field": "salary" } } } } GET test_search_index/_search { "size":0, "aggs":{ "min_age":{ "min": { "field": "age" } } } } GET test_search_index/_search { "size":0, "aggs":{ "max_age":{ "max": { "field": "age" } } } } GET test_search_index/_search { "size":0, "aggs":{ "avg_age":{ "avg": { "field": "age" } } } } GET test_search_index/_search { "size":0, "aggs":{ "sum_age":{ "sum": { "field": "age" } } } } GET test_search_index/_search { "size": 0, "aggs": { "min_age": { "min": { "field": "age" } }, "max_age": { "max": { "field": "age" } }, "avg_age": { "avg": { "field": "age" } }, "sum_age": { "sum": { "field": "age" } } } } GET test_search_index/_search { "size":0, "aggs":{ "count_of_job":{ "cardinality": { "field": "job.keyword" } } } } GET test_search_index/_search { "size":0, "aggs":{ "stats_age":{ "stats": { "field": "age" } } } } GET test_search_index/_search { "size":0, "aggs":{ "exstats_salary":{ "extended_stats": { "field": "salary" } } } } GET test_search_index/_search { "size":0, "aggs":{ "per_salary":{ "percentiles": { "field": "salary" } } } } GET test_search_index/_search { "size": 0, "aggs": { "per_age": { "percentiles": { "field": "salary", "percents": [ 95, 99, 99.9 ] } } } } GET test_search_index/_search { "size": 0, "aggs": { "per_salary": { "percentile_ranks": { "field": "salary", "values": [ 11000, 30000 ] } } } } GET test_search_index/_search { "size": 0, "aggs": { "jobs": { "terms": { "field": "job.keyword", "size": 10 }, "aggs": { "top_employee": { "top_hits": { "size": 10, "sort": [ { "age": { "order": "desc" } } ] } } } } } } # bucket GET test_search_index/_search { "size": 0, "aggs": { "jobs": { "terms": { "field": "job", "size": 5 } } } } GET test_search_index GET test_search_index/_search { "size": 0, "aggs": { "salary_range": { "range": { "field": "salary", "ranges": [ { "key":"<10000", "to": 10000 }, { "from": 10000, "to": 20000 }, { "key":">20000", "from": 20000 } ] } } } } GET test_search_index/_search { "size": 0, "aggs": { "date_range": { "range": { "field": "birth", "format": "yyyy", "ranges": [ { "from":"1980", "to": "1990" }, { "from": "1990", "to": "2000" }, { "from": "2000" } ] } } } } GET test_search_index/_search { "size": 0, "aggs": { "date_range": { "range": { "field": "birth", "format":"yyyy", "ranges": [ { "to": "now-30y/y" }, { "from": "now-30y/y", "to": "now-20y/y" }, { "from": "now-20y/y" } ] } } } } GET test_search_index/_search { "size":0, "aggs":{ "salary_hist":{ "histogram": { "field": "salary", "interval": 5000, "extended_bounds": { "min": 0, "max": 40000 } } } } } GET test_search_index/_search { "size":0, "aggs":{ "salary_hist":{ "histogram": { "field": "salary", "interval": 5000, "extended_bounds": { "min": 0, "max": 40000 } } } } } GET test_search_index/_search { "size":0, "aggs":{ "by_year":{ "date_histogram": { "field": "birth", "interval": "year", "format":"yyyy" } } } } # bucket more GET test_search_index/_search { "size": 0, "aggs": { "jobs": { "terms": { "field": "job.keyword", "size": 10 }, "aggs": { "age_range": { "range": { "field": "age", "ranges": [ { "to": 20 }, { "from": 20, "to": 30 }, { "from": 30 } ] } } } } } } GET test_search_index/_search { "size": 0, "aggs": { "jobs": { "terms": { "field": "job.keyword", "size": 10 }, "aggs": { "salary": { "stats": { "field": "salary" } } } } } } # scope GET test_search_index/_search { "size":0, "aggs":{ "jobs":{ "terms": { "field": "job.keyword", "size": 10 } } } } GET test_search_index/_search { "size":0, "query":{ "match": { "username": "alfred" } }, "aggs":{ "jobs":{ "terms": { "field": "job.keyword", "size": 10 } } } } # filter GET test_search_index/_search { "size": 0, "aggs": { "jobs_salary_small": { "filter": { "range": { "salary": { "to": 10000 } } }, "aggs": { "jobs": { "terms": { "field": "job.keyword" } } } }, "jobs": { "terms": { "field": "job.keyword" } } } } #post-filter GET test_search_index/_search { "aggs": { "jobs": { "terms": { "field": "job.keyword" } } }, "post_filter": { "match":{ "job.keyword":"java engineer" } } } #global GET test_search_index/_search { "query": { "match": { "job.keyword": "java engineer" } }, "aggs": { "java_avg_salary": { "avg": { "field": "salary" } }, "all": { "global": {}, "aggs": { "avg_salary": { "avg": { "field": "salary" } } } } } } #sort GET test_search_index/_search { "size": 0, "aggs": { "jobs": { "terms": { "field": "job.keyword", "size": 10 } } } } GET test_search_index/_search { "size": 0, "aggs": { "jobs": { "terms": { "field": "job.keyword", "size": 10, "order": [ { "avg_salary": "desc" } ] }, "aggs": { "avg_salary": { "avg": { "field": "salary" } } } } } } GET test_search_index/_search { "size": 0, "aggs": { "jobs": { "terms": { "field": "job.keyword", "size": 10, "order": [ { "stats_salary.sum": "desc" } ] }, "aggs": { "stats_salary": { "stats": { "field": "salary" } } } } } } GET test_search_index/_search { "size": 0, "aggs": { "salary_hist": { "histogram": { "field": "salary", "interval": 5000, "order": { "age>avg_age": "desc" } }, "aggs": { "age": { "filter": { "range": { "age": { "gte": 10 } } }, "aggs": { "avg_age": { "avg": { "field": "age" } } } } } } } } # pipeline aggs GET test_search_index/_search { "size":0, "aggs":{ "jobs":{ "terms": { "field": "job.keyword", "size": 10 }, "aggs":{ "avg_salary":{ "avg": { "field": "salary" } } } }, "min_salary_by_job":{ "min_bucket": { "buckets_path": "jobs>avg_salary" } } } } GET test_search_index/_search { "size":0, "aggs":{ "jobs":{ "terms": { "field": "job.keyword", "size": 10 }, "aggs":{ "avg_salary":{ "avg": { "field": "salary" } } } }, "max_salary_by_job":{ "max_bucket": { "buckets_path": "jobs>avg_salary" } } } } GET test_search_index/_search { "size":0, "aggs":{ "jobs":{ "terms": { "field": "job.keyword", "size": 10 }, "aggs":{ "avg_salary":{ "avg": { "field": "salary" } } } }, "avg_salary_by_job":{ "avg_bucket": { "buckets_path": "jobs>avg_salary" } } } } GET test_search_index/_search { "size":0, "aggs":{ "jobs":{ "terms": { "field": "job.keyword", "size": 10 }, "aggs":{ "avg_salary":{ "avg": { "field": "salary" } } } }, "sum_salary_by_job":{ "sum_bucket": { "buckets_path": "jobs>avg_salary" } } } } GET test_search_index/_search { "size":0, "aggs":{ "jobs":{ "terms": { "field": "job.keyword", "size": 10 }, "aggs":{ "avg_salary":{ "avg": { "field": "salary" } } } }, "stats_salary_by_job":{ "stats_bucket": { "buckets_path": "jobs>avg_salary" } } } } GET test_search_index/_search { "size":0, "aggs":{ "jobs":{ "terms": { "field": "job.keyword", "size": 10 }, "aggs":{ "avg_salary":{ "avg": { "field": "salary" } } } }, "percentiles_salary_by_job":{ "percentiles_bucket": { "buckets_path": "jobs>avg_salary" } } } } #derivative GET test_search_index/_search { "size": 0, "aggs": { "birth": { "date_histogram": { "field": "birth", "interval": "year", "min_doc_count": 0 }, "aggs": { "avg_salary": { "avg": { "field": "salary" } }, "derivative_avg_salary": { "derivative": { "buckets_path": "avg_salary" } } } } } } GET test_search_index/_search { "size": 0, "aggs": { "birth": { "date_histogram": { "field": "birth", "interval": "year", "min_doc_count": 0 }, "aggs": { "avg_salary": { "avg": { "field": "salary" } }, "mavg_salary": { "moving_avg": { "buckets_path": "avg_salary" } } } } } } GET test_search_index/_search { "size": 0, "aggs": { "birth": { "date_histogram": { "field": "birth", "interval": "year", "min_doc_count": 0 }, "aggs": { "avg_salary": { "avg": { "field": "salary" } }, "cumulative_salary": { "cumulative_sum": { "buckets_path": "avg_salary" } } } } } } # shard_size GET test_search_index/_search { "size": 0, "aggs": { "jobs": { "terms": { "field": "job.keyword", "size": 2, "shard_size": 10, "show_term_doc_count_error": true } } } } GET test_search_index GET test_order/_search GET test_order GET test_order/_search { "size":0, "aggs":{ "customer_count":{ "cardinality": { "field": "CustomerID.keyword" } } } } GET test_order_one_shard/_search { "size":0, "aggs":{ "customer_count":{ "cardinality": { "field": "CustomerID.keyword" } } } } GET test_order_one_shard/_search { "size":0, "aggs":{ "states":{ "terms":{ "field":"CustomerID.keyword", "size":1, "show_term_doc_count_error": true } } } } GET test_order_one_shard GET test_order/_search { "size":0, "aggs":{ "states":{ "terms":{ "field":"CustomerID.keyword", "size":1, "shard_size": 10000, "show_term_doc_count_error": true } } } }
Search的运行机制
query 和 fetch





相关性算法




search 排序








Fielddata


fielddata 只对 text 类型生效
Doc Values


docvalue_fields

分页与遍历

from size




scroll





参考 https://www.elastic.co/guide/cn/elasticsearch/guide/cn/scroll.html
启用游标查询可以通过在查询的时候设置参数 scroll 的值为我们期望的游标查询的过期时间。 游标查询的过期时间会在每次做查询的时候刷新,所以这个时间只需要足够处理当前批的结果就可以了,而不是处理查询结果的所有文档的所需时间。 这个过期时间的参数很重要,因为保持这个游标查询窗口需要消耗资源,所以我们期望如果不再需要维护这种资源就该早点儿释放掉。 设置这个超时能够让 Elasticsearch 在稍后空闲的时候自动释放这部分资源。
只有设置 滚动的时间不要太长即可,一般不会存在占用大量内存的问题, 因为 es 会释放的。

Search_after






es 术语

因为 es 6.0 版本之后, 去掉了 index 下面的 type 类型,
只有一个 type 类型了,
因此把 index 看做 是 数据库中的一张 表即可


document


document MetaData

不推荐使用 _all

Index


index API


Document API




批量创建文档


update 当文档不存在就会报错。
如果是 index 那么文档存在就覆盖,不存在就创建

批量查询


倒排索引与分词


正排索引与倒排索引












es 倒排索引

分词

分词器


Analyze API
当发现查询 不到的时候 或者与预期不一样的时候,既可以去看看分词是怎样的,可以通过 分词 analyze 去分析排查




standard 是 es 默认的分词器


自带分词器








当不想对文本进行分词就可以使用这个


中文分词



自定义分词




自定义 Tokennizer

搜索的 自动提示 可以使用 NGram

自定义 Token Filters


自定义分词API






分词使用说明




es Mapping


自定义mapping




copy to

index

不索引,设置为 false 可以节省 磁盘和内存 空间
index_options




默认es 对 空值会忽略该值
数据类型

复杂数据类型

专用类型

多字段特性

Dynamic Mapping














热门排行