Elasticsearch
其实是一个数据库。是基于java的开源分布式搜索引擎。拥有分布式,零配置,自动发现,索引自动分片,索引副本机制,restful风格接口,多数据源,自动搜索负载等功能
Logstash
基于java,是一个开源的用于收集,分析和存储日志的工具。收集到数据之后可以通过Kibana来进行大数据的可视化
Kibana
基于nodejs,也是一个开源和免费的工具。也是一个展示数据的可视化组件,可以理解为它是mysql的navicate。可以为Logstash和Elasearch提供日志分析友好的web界面,可以汇总、分析和搜索重要的数据日志。通过Kinana可以通过各种图表进行高级数据分析及展示
Beats
是elastic公司开源的一款采集系统监控数据的代理agent,是在被监控服务器上以客户端形式运行的数据收集器的统称。它可以直接把数据发送给elasticsearch或者通过Logstash发送给ES
Elasticsearch术语
文档document,用户存储在es中的数据文档,它是es中存储的最小单元。相当于mysql数据表中的数据。每一个文档都有一个唯一的标识即_id,可以自行指定也可以通过es生成。每一个文档都是一个json对象
索引index,index类比为mysql的表
结点node,一个node就是es的一个运行实例
集群cluster,有一个或多个节点组成,对外提供服务
Elaticsearch查询:
1.查询字符串,也称简单查询
2.通过DSL语句来进行查询,是以json请求体以api方式查询的
GET _search
{
"query": {
"match_all": {}
}
}
# 查看索引
GET /_cat/indices
# 创建索引
PUT test2
# 删除索引
DELETE test2
# 在索引内添加数据
PUT test2/_doc/4
{
"name": "xiaoming",
"age": 21,
"location": "shanghai "
}
# 查看索引内的数据
GET test2/_doc/1
# 查看索引内的所有数据
GET test2/_search
# 更新索引内的数据
POST test2/_update/3
{
"doc": {
"location": "北京市朝阳区"
}
}
# 删除索引内的数据
DELETE test2/1/AXQwDfEgcGc6QGpxi6ce
# 删除索引,即删除索引内的所有数据
DELETE test2
# 查看索引内值为指定值的数据
GET test2/_search?q=location="shanghai"
# 通过DSL来查询数据 它是以json请求体来实现的
# title text 以or的形式匹配
# title.keyword 关键字 不会进行分词
GET test2/_search
{
"query":{
"match": {
"title": "炮兵怕把标兵碰 abc"
}
}
}
# select * from table
GET test2/_search
{
"query": {
"match_all": {}
}
}
# 对结果进行排序
GET test2/_search
{
"query":{
"match": {
"location": "shanghai"
}
},
"sort":{
"age": {
"order": "desc"
}
}
}
# 分页查询 size限定查询结果的显示输出
GET test2/_search
{
"query": {
"match_all": {}
},
"from": 0,
"size": 2
}
# 布尔查询(where)
# must(and) should(or) must_not(not) filter(过滤条件)
GET test2/_search
{
"query":{
"bool": {
"must": [
{
"match": {
"location": "shanghai"
}
},
{
"match": {
"age": 21
}
}
]
}
}
}
# should(or)
GET test2/_search
{
"query":{
"bool": {
"should": [
{
"match": {
"location": "shanghai"
}
},
{
"match": {
"age": 21
}
}
]
}
}
}
# must_not(not)
GET test2/_search
{
"query":{
"bool": {
"must_not": [
{
"match": {
"location": "shanghai"
}
},
{
"match": {
"age": 21
}
}
]
}
}
}
# must(and) filter
GET test2/_search
{
"query":{
"bool": {
"must": [
{
"match": {
"location": "shanghai"
}
}
],
"filter": [
{
"range":{
"age":{
"gt": 18,
"lt": 20
}
}
}
]
}
}
}
# 结果过滤字段 _source(类似于select)
GET test2/_search
{
"query": {
"match_all": {}
},
"_source": ["name", "age"]
}
# 高亮显示。可以使用pre_tags和post_tags对高亮进行自定义
GET test2/_search
{
"query": {
"match": {
"location": "shanghai"
}
},
"highlight": {
"pre_tags": "<br>",
"post_tags": "</br>",
"fields": {
"location": {}
}
}
}
# 聚合函数 aggs
#Avg 平均值
#Max 最大值
#Min 最小值
#Sum 求和
GET test2/_search
{
"query": {
"match": {
"location.keyword": "shanghai"
}
},
"aggs": {
"age_avg": {
"avg": {
"field": "age"
}
}
},
"_source": ["name", "age"],
"size": 0
}
#Max 最大值
GET test2/_search
{
"query": {
"match": {
"location": "shanghai"
}
},
"aggs": {
"age_max": {
"max": {
"field": "age"
}
}
},
"_source": ["name", "age"],
"size": 0
}
# 分组查询 使用range这个函数进行分组,filed指定以谁分组
# 查询所有人的年龄段,并且按照10~20,20~30两个分组,并且算出每组的平均年龄,下面的age_group只是个别名
GET test2/_search
{
"query": {
"match_all": {}
},
"aggs": {
"age_group": {
"range": {
"field": "age",
"ranges": [
{
"from": 10,
"to": 20
},
{
"from": 20,
"to": 30
}
]
},
"aggs": {
"age_avg": {
"avg": {
"field": "age"
}
}
}
}
},
"size": 0
}
# 对索引的settings进行设置
PUT test2/_settings
{
"index": {
"blocks": {
"read_only_allow_delete": "false"
}
}
}
# _doc是用来做什么的
# 6.0之前
# 映射类型用以表示被索引的文档或实体的类型,每个映射类型都可以有自己的字段
# 每个文档都分配一个映射类型
# 每个映射类型都可以有自己的字段
#索引在6.x中创建只允许每个索引使用单一类型,类型可以使用任何名称,但只能有一个,首选的类型名称是_doc
#在7.0中,_doc是路径的一个永久部分,它表示端点名称,而不是文档类型
# mappings
# 查看索引信息。结果分为两部分mappings和settings
# mappings包含各个字段详细映射关系
# settings 包含索引创建时间、主副分片信息、uuid等等
GET test2
# 映射mappings就是es中定义的表结构,如果未定义mappings,会根据字段的值来判断所属的类型自动创建
# 哪些字符串应该被视为全文字段
# 哪些字段包含数字、日期或者地理位置
# 定义日期格式
# 自定义的规则,用来控制动态添加字段的映射
# 字段数据类型
# 简单类型,如文本(text)、关键字(keyworkd)、日期(date)、整型(long)、双精度(double)、布尔(boolean)或ip
# 可以是支持JSON的层次结构性质的类型,如对象或嵌套
# 或者一种特殊类型,如geo_point、geo_shape或completion
#mappings 的三种模式
#映射mappings就是elasticsearch中定义的表结构。会影响新字段是否能插入,存储字段的类型,能够以新字段为查询条件。
#动态映射(默认dynamic)会根据字段的值自动创建类型
#静态映射(设置 'dynamic':false) 不会为新增字段建立映射关系, 会出现在查询结果中但是以新添加的字段为查询条件查询不到数据。
# 会严格映射('dynamic':strict)不能增加新的字段,会报错
PUT mappings_test1
{
"mappings": {
"properties": {
"name": {
"type": "text"
},
"age": {
"type": "long"
}
}
}
}
PUT mappings_test2
{
"mappings": {
"dynamic": false,
"properties": {
"name": {
"type": "text"
},
"age": {
"type": "long"
}
}
}
}
PUT mappings_test3
{
"mappings": {
"dynamic": "strict",
"properties": {
"name": {
"type": "text"
},
"age": {
"type": "long"
}
}
}
}
# 停用词
#1.有些词在文本中出现的频率非常高,但是对文本所携带的信息基本不产生影响
#2.一些英文,如a、an、the、of
#3.中文,如的、了、着、是、标点符号等
#4.文本经过分词之后,停用词通常被过滤掉,不会进行索引
#5.在检索的时候,用户的查询中如果含有停用词,检索系统也会将其过滤掉(因为用户输入的查询字符串也要进行分词处理)
#6.排除停用词可以加快建立索引的速度,减小索引库文件的大小
# 原始文本 share your experience with NoSql & big data technoloqies
# 1.首先进行字符过滤,比如span标签
# 2.将一些特殊字符进行转换,比如&->and。share your experience with NoSql and big data technoloqies
# 3.标准分词器分词。share|your|experience|with|NoSql|and|big|data|technoloqies
# 4.分词过滤器。是将已分的词进行加工。大小写转换>去掉停用词>同义词的转换。
# 5.进行倒排索引处理
# 分词器
# standard-默认分词器,按字切分,区分中英文,英文按照空格切分,同时进行大小写转换,小写处理,去掉特殊符号
# simple-按照非字母切分(符号被过滤),小写转换。先按照空格分词,不是英文不分词
# stop-小写处理,停用词过滤(the,a,is)
# whitespace-按照空格切分,不转小写
# keyword-不分词,直接将输入当作输出
# patter-正则表达式,默认\W+(非字符分割)
# language-提供了30多种常见语言的分词器
# customer-自定义分词器
POST _analyze
{
"analyzer": "standard",
"text": "Hello World&端午节"
}
# 不会拆分中文
POST _analyze
{
"analyzer": "simple",
"text": "Hello World&端午节"
}
# 仅仅只有按空格分词,英文不进行大小写转换,中文不分词
POST _analyze
{
"analyzer": "whitespace",
"text": "Hello World&端午节"
}
# standard、simple、whitespace对中文支持的都不太好
# IK分词器,它是ES一种插件,需要安装
# IK有两种颗粒度的拆分,中文词汇的拆分,而不是拆分所有的中文的汉字
# ik_smart 会做最粗力度的拆分
# ik_max_word 会将文本做最细粒度的拆分
POST _analyze
{
"analyzer": "ik_smart",
"text": "2020秋男子UltraBOOST运动跑步鞋BB6168 F36641"
}
POST _analyze
{
"analyzer": "ik_max_word",
"text": "专柜正品NIKE耐克 NSW 男子泼墨印花圆领短袖T恤 CW0381-010-031"
}
# 设定mappings的分词器,在指定字段类型时指定分词器
PUT test1
PUT test2
{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "ik_max_word"
}
}
}
}
# 怎么看IK分词器和默认分词器的区别呢
# 会把所有包含兵这个字的文档输出
GET test1/_search
{
"query": {
"match": {
"title": "标兵"
}
}
}
# 有个更好的精准输出
GET test2/_search
{
"query": {
"match": {
"title": "标兵"
}
}
}
# elasticsearch 主要功能是搜索功能,只不过有时候用到了搜索引擎的部分功能用于存储数据,这些数据是方便后续kibana可视化分析和展示
# 倒排索引
# Term(单词),一段文本经过分析之后就成为了一串单词,这一个个单词就叫term。相当于词典中的词语
# Term Index(单词索引),为了能够更快找到某个单词会为这个单词建立索引。相当于词典的目录索引
# Term Dictionary(单词字典),里面维护了很多的Term,是一个Term的集合。相当于语词典的本身
# Posting List(倒排列表),记录了出现某个单词的所有文档和文档列表以及该单词出现在文档中的位置信息,每条记录被称为倒排项,是一个数组存储了所有符合某个单词的文档id
# 在倒排索引中,我们通过单词的索引可以找到单词在Term Dictionary中的位置,进而找到posting list,通过posting list就可以查找到文档所在的id,通过id就可以找到所在的文档
# 倒排项是记录出现某个单词的所有文档id,以及在文档中的位置信息,词频等等,会为每个字段建立一个倒排索引
# ES会对每个字段建立一个倒排索引
PUT /shakespeare
{
"mappings": {
"properties": {
"speaker": {"type": "keyword"},
"play_name": {"type": "keyword"},
"line_id": {"type": "integer"},
"speech_number": {"type": "integer"}
}
}
}
GET /_cat/indices
GET /shakespeare/_count
PUT /logstash-2015.05.20
{
"mappings": {
"properties": {
"geo": {
"properties": {
"coordinates": {
"type": "geo_point"
}
}
}
}
}
}
GET logstash*/_search
{
"query": {
"match": {
"geo.src.keyword": "CN"
}
}
}
# pipeline 管道聚合分析,支持对聚合分析的结果再次进行聚合分析,支持链式调用
# Sibling - 结果和现有分析结果同级
# max/min/avg&sum bucket
# stats/extended status bucket
# percentiles bucket
# Parent - 结果内嵌到现有的聚合分析结果之中
# derivate - 求导
# cumultive sum - 累计求和
# moving function - 移动平均
# 使用Sibling求出所有工作工资最低的
# 首选需要对工作进行分筒,接着求各工作工资的平均值,最后求出工资最低的那个工作
GET employees/_search
{
"size": 0,
"aggs": {
"job_terms": {
"terms": {
"field": "job.keyword",
"size": 10
},
"aggs": {
"avg_salary": {
"avg": {
"field": "salary"
}
}
}
},
"min_salary_by_job": {
"min_bucket": {
"buckets_path": "job_terms>avg_salary"
}
}
}
}
# 使用Parent求出薪资待遇的累加和,首选通过年龄输出个直方图,再通过这个直方图算出当前薪资待遇的平均值,再通过平均值再来算薪资待遇的累加和
GET employees/_search
{
"size": 0,
"aggs": {
"age": {
"histogram": {
"field": "age",
"interval": 5
},
"aggs": {
"avg_salary": {
"avg": {
"field": "salary"
}
},
"sum_avg_salary": {
"cumulative_sum": {
"buckets_path": "avg_salary"
}
}
}
}
}
}
GET employees/_search
{
"query": {
"match_all": {}
}
}
GET employees/_search
{
"size": 0,
"aggs": {
"job_terms": {
"terms": {
"field": "job.keyword",
"size": 10
}
}
}
}
PUT douyin_data/_doc/1
{
"name": "xiaoming",
"age": 21,
"location": "shanghai",
"crawl_time": "2020-06-29 08:44:18"
}
python操作ES
import time
from elasticsearch import Elasticsearch, helpers
es = Elasticsearch(hosts="127.0.0.1:9200")
print(es.info())
def timer(func):
def wrapper(*args, **kwargs):
start_time = time.time()
res = func(*args, **kwargs)
print("共消耗%.3f秒" % (time.time() - start_time))
return res
return wrapper # return到了wrapper就形成了闭包
@timer
def handle_batch():
# 方式1,传统插入数据方式,通过遍历的方式进行插入,共消耗52.577秒
# for value in range(10000):
# es.index(index="value_demo", body={"value": value})
# 方式2,优化:先组装成一个大的列表,通过helplers模块将这个大的列表一次性插入进去
# 通过helpers.bulk方法插入数据,一个大的列表共消耗1.415秒
# data = [{"_index": "value_demo", "_source": {"value": value}} for value in range(10000)] # 列表生成式的方式生成
# # 通过helpers插入数据
# helpers.bulk(es, data)
# 方式3,优化通过迭代器,把数据的组装放到了bulk中,也就是ES里面,ES处理数据肯定是比python处理快的
# 有一个缺陷,如果列表数据非常大,会先把内存撑爆
# 通过迭代器,构造一个迭代器,把这个迭代器放到helpers.bulk方法中去
# 共消耗0.000秒
for value in range(10000):
yield {"_index": "value_demo", "_source": {"value": value}, "_type": "doc"} # 通过yield将改成了迭代器形式
def handle_simple():
# 通过python进行基本的增删改查
# 创建索引
# es.indices.create(index="test5")
# 查看索引
print(es.cat.indices())
# 删除索引
# es.indices.delete(index="test5")
# 创建索引并插入数据
# print(es.index(index="test5", body = {"name": "zhangsan", "age": 18})) # 直接插入
# print(es.index(index="test5", doc_type = "_doc", body = {"name": "zhangsan", "age": 18}, id=1))
# print(es.search(index = "test5"))
# print(es.get(index = "test5", id = 1))
# dsl方法
# body = {
# "query": {
# "match": {
# "name": "zhangsan"
# }
# }
# }
# search_res = es.search(index = "test5", body = body)
# print(search_res)
# 数据的更新
# body = {
# "doc": {
# "tags": "测试"
# }
# }
# print(es.update(index = "test5", doc_type = "_doc", id=1, body = body))
# 数据的删除
# es.delete(index = "test5", id = 1)
if __name__ == '__main__':
# handle_simple() # 基本的增删改查
# handle_batch() # 高级:批量的操作
helpers.bulk(es, actions=handle_batch()) # 高级:迭代器的形式。把迭代器放到ES里面,ES来进行解析进而执行插入,从而减少时间的消耗
# print(es.count(index="value_demo"))'
总结一下:
如果只是需要借助ES实现宽表功能方便查询
需要考虑的事情:
1.宽表中都需要哪些字段
2.这些字段的mappings应该是什么样的(会影响新字段是否能插入,存储字段的类型,能否以新字段为查询条件。)
3.对定好的字段该如何使用哪种分词器来方便实现查询的初衷
============================================================
示例数据:
https://www.elastic.co/guide/cn/kibana/current/tutorial-load-dataset.html
kibana如何加载ES中的数据,需要配置索引模式
============================================================
索引模式(index pattern)
是kibana用来从ES取数据使用的,ES存入数据之后如果想要通过kibana读取并且展示相关的数据,就需要配置索引模式
一个索引模式是可以匹配多个带可选通配符的字符串,它们是具有共同特征的索引
指定shakes*作为
加载的索引只要名称匹配都可以正常工作。
通过kibana中的索引模式将ES中的数据索引到kibana
============================================================
索引模式是kibana用来从es取数据使用的
============================================================
kibana中的discover
可以简单的对数据进行分析和展示
1.在柱形图中可以拉取包含对应的柱形,可以快速选中查看里面的数据
2.搜索的使用(查询方法1)
通过在搜索中搜索日志里面的字段就可以索引到当前这些数据的字段。如geo.src.keyword:"CN",搜索的结果是geo.src.keyword字段为CN的文档
3.查询方法2,开发开发工具中执行DSL语句
GET logstash*/_search
{
"query": {
"match": {
"geo.src.keyword": "CN"
}
}
}
4.查询方法3,点击KQL,将Kibana 查询语言开关关闭(因为kibana默认使用的kibana的查询语言)
只要DSL语句中query的value内容
{"match":{"geo.src.keyword":"CN"}}
discover数据的筛选,筛选功能
可以实现对查询的数据进行再次筛选
字段-运算符-值
比如字段选中@tags,运算符选择是,值选择warning,这样所有@tags为warning的地方都会被标黄
使用里面的排除结果可以实现取反的功能
选定字段的功能,可以定制数据的显示
表是对当前一条数据的格式化
里面的放大镜,点击是用来筛选的
============================================================
pipeline 管道聚合分析,支持对聚合分析的结果再次进行聚合分析,支持链式调用
Sibling - 结果和现有分析结果同级
max/min/avg&sum bucket
stats/extended status bucket
percentiles bucket
Parent - 结果内嵌到现有的聚合分析结果之中
derivate - 求导
cumultive sum - 累计求和
moving function - 移动平均
Timelion:
Timelion是一个时间序列数据的可视化,可以结合在一个单一的可视化完全独立的数据源。它是由一个简单的表达式语言驱动的,用来检索时间序列数据,进行计算,然后可视化结果
Timelion可以解决的问题:
每个唯一用户在一段时间内查看多少页
本周五和上周五之间的流量有什么不同
日本百分之几的人口今天来到我的网站
标准普尔500指数10日移动平均线是多少
过去两年内收到的所有搜索请求累计总和是多少
请求语法所支持的函数分类:
数据源设定类
.elasticsearch():从ES读取数据
.es(q="querystring", metric="cardinality:uid", index="logstash-*", offset="-1d"): .elasticsearch的缩写 q是查询的关键字 metric是对哪个关键字进行统计或分析 index是指定的哪个索引模式 offset是设置日期的分片是对当前时间和历史数据进行比对的
.graphite(metric="path.to.*.data", offset="-1d"):从graphite读取数据
.quandl():从quandl.com读取quandl码
.worldbank_indicators():从worldbank.org读取国家数据
.wbi():.worldbank_indicators()的简写
.worldbank():从worldbank.org读取数据
.wb():worldbank()的简写
可视化效果类
.bars($width):用柱状图展示数组
.lines($width, $fill, $show, $steps):用折线图展示数组
.points():用散点图展示数组
.color("#c6c6c6"):改变颜色
.hide():隐藏该数组
.label("change from %s"):标签
.legend($position, $column):图列位置
.static(value=1024, label="1k", offset="-1d", fit="scale"):在图形上绘制一个固定值
.value():.staic()的简写
.title(title="qps"):图表标题
.trend(mode="linear", start=0, end=-10): 采用linear或log回归算法绘制趋势图
.yaxis($yaxis_number, $min, $max, $position):设置Y轴属性,.yaxis(2)表示第二根Y轴
数据运算类
.abs():对整个数组元素求绝对值
.precision($number):浮点数精度
.cusum($base):数组元素之和,再加上$base
.derivative():对数组求导数
.divide($divisor):数组元素除法
.multiply($multiplier):数组元素乘法
.subtract($term):数组元素减法
.sum($term):数组元素加法
.add():同.sum()
===========================================================
.es(index=logstash*,metric=count,offset="-1d").label("昨日").lines(fill=1,width=0.5).color(gray),.es(index=logstash*,metric=count).label("今日").title("访问统计").color(#1E90FF)
.es(index=logstash*,q="geo.src.keyword:CN",metric=count,split=machine.os.keyword:3)
今日和昨日流量对比及添加流量告警线
.es(index=logstash*,metric=sum:bytes,offset=-1d).label("昨日"),.es(index=logstash*,metric=sum:bytes).label("今日"),.static(1000000).label("告警线").color("red")
访问量和流量的对比
(.es(index=logstash*).label("请求计数"),.es(index=logstash*,metric=sum:bytes).label("流量计数")).range(0,10000)
===========================================================