avatar

目录
ELK-搜索引擎

参考:http://blog.sina.com.cn/s/blog_c30a9e680102z42l.html

[toc]

ElasticSearch简介

Elasticsearch

一个基于Apache Lucene(TM)的开源搜索引擎。

ES能做什么?

全文检索(全部字段)、模糊查询(搜索)、数据分析(提供分析语法,例如聚合)

Elasticsearch使用案例

同类产品

Solr、ElasticSearch、Hermes(腾讯)(实时检索分析)

Lucene是一个开放源代码的全文检索引擎工具包,但它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎

ElasticSearch

准备工作

安装Centos7、内存2G以上、java1.8、关闭防火墙

ElasticSerach单机安装

只能写192.168那个地址,写hostname不行,原因未知。

Elasticsearch的交互方式

1、restfull

2、程序语言的客户端

Elasticsearch操作工具

  • REST访问ES方式
    • postman\浏览器
    • Kibana的Dev Tools

Elasticsearch数据存储

存储方式

(1)面向文档

这也是Elasticsearch能够执行复杂的全文搜索的原因之一。

(2)JSON

在Elasticsearch中将对象转化为JSON并做索引要比在表结构中做相同的事情简单的多。

存储结构

结构图:

image-20191226194415808

比如创建文档语句:

Code
1
2
3
4
5
PUT mxx/doc/1
{
"name":"zhangsan",
"age":10
}

查询这条数据:GET mxx/doc/1,返回结果:

Code
1
2
3
4
5
6
7
8
9
10
11
{
"_index": "mxx",
"_type": "doc",
"_id": "1",
"_version": 1,
"found": true,
"_source": {
"name": "zhangsan",
"age": 10
}
}

解释:

Code
1
2
3
4
5
6
7
_index:文档所在索引名称
_type:文档所在类型名称
_id:文档唯一id
_uid:组合id,由_type和_id组成(6.x后,_type不再起作用,同_id)
_source:文档的原始Json数据,包括每个字段的内容
_all:将所有字段内容整合起来,默认禁用(用于对所有字段内容检索)
_version:乐观锁,用于并发

名词:

  • 索引 index(对应数据库)

    一个索引就是一个拥有几分相似特征的文档的集合。比如说,你可以有一个客户数据的索引,另一个产品目录的索引,还有一个订单数据的索引。一个索引由一个名字来标识(必须全部是小写字母的),并且当我们要对对应于这个索引中的文档进行索引、搜索、更新和删除的时候,都要使用到这个名字。在一个集群中,可以定义任意多的索引。

  • 类型 type(对应表)

    Es6之后,一个index中只能有一个type

  • 字段Field

    相当于是数据表的字段,对文档数据根据不同属性进行的分类标识

  • document

    一个文档是一个可被索引的基础信息单元。文档以JSON格式来表示。在一个index/type里面,你可以存储任意多的文档。

Elasticsearch检索

检索文档

Mysql : select * from user where id = 1

ES : GET /mxx/doc/1

我们通过HTTP方法GET来检索文档,同样的,我们可以使用DELETE方法删除文档,使用HEAD方法检查某文档是否存在。如果想更新已存在的文档,我们只需再PUT一次(_version字段+1)。

简单检索

Mysql : select * from user

ES : GET /mxx/doc/_search

返回:

Code
1
响应内容不仅会告诉我们哪些文档被匹配到,而且这些文档内容完整的被包含在其中—我们在给用户展示搜索结果时需要用到的所有信息都有了。

全文检索

ES : GET /mxx/doc/_search?q=zhangsan

查询出所有文档字段值为haha的文档。(字段值需要完全匹配)

搜索(模糊查询)

GET /mxx/doc/_search?q=haha

查询出所有文档字段值分词后包含hello的文档

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
PUT /mxx/doc/1
{
"name":"zhangsan haha",
"age":12
}

PUT /mxx/doc/2
{
"name":"lisi haha",
"age":10
}

GET /mxx/doc/_search?q=haha

聚合

Group by

Elasticsearch有一个功能叫做聚合(aggregations),它允许你在数据上生成复杂的分析统计。它很像SQL中的GROUP BY但是功能更强大。

比如,Group by一下age这个字段。

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
PUT /mxx/doc/3
{
"name":"wangwu",
"age":10
}

GET /mxx/doc/_search
{
"aggs": {
"all_ages": {
"terms": { "field": "age" }
}
}
}

查询结果:

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
...
"aggregations": {
"all_ages": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": 10,
"doc_count": 2
},
{
"key": 12,
"doc_count": 1
}
]
}
}
}

这些数据并没有被预先计算好,它们是实时的从匹配查询语句的文档中动态计算生成的。

还可以添加约束(所有姓”Smith”的人的共同兴趣爱好):

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
GET /mxx/doc/_search
{
"query": {
"match": {
"last_name": "smith"
}
},
"aggs": {
"all_interests": {
"terms": {
"field": "interests"
}
}
}
}

Elasticsearch搜索原理

正排索引和倒排索引

分词

  • 分词机制

  • 分词API

  • Elasticsearch自带的分词器

  • 中文分词

  • Character Filters

    在进行Tokenizer之前对原始文本进行处理,如增加、删除或替换字符等

  • Token Filter

    对输出的单词(term)进行增加、删除、修改等操作

  • 自定义分词api

    Code
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    PUT my_analyzer
    {
    "settings": {
    "analysis": {
    "analyzer": {
    "my":{
    "tokenizer":"punctuation",
    "type":"custom",
    "char_filter":["emoticons"],
    "filter":["lowercase","english_stop"]
    }
    },
    "tokenizer": {
    "punctuation":{
    "type":"pattern",
    "pattern":"[.,!?]"
    }
    },
    "char_filter": {
    "emoticons":{
    "type":"mapping",
    "mappings":[
    ":)=>_happy_",
    ":(=>_sad_"
    ]
    }
    },
    "filter": {
    "english_stop":{
    "type":"stop",
    "stopwords":"_english_"
    }
    }
    }
    }
    }

    测试:

    Code
    1
    2
    3
    4
    5
    POST my_analyzer/_analyze
    {
    "analyzer": "my",
    "text":"l'm a :) person,and you?"
    }

    结果:

    Code
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    {
    "tokens": [
    {
    "token": "l'm a _happy_ person",
    "start_offset": 0,
    "end_offset": 15,
    "type": "word",
    "position": 0
    },
    {
    "token": "and you",
    "start_offset": 16,
    "end_offset": 23,
    "type": "word",
    "position": 1
    }
    ]
    }
  • 分词使用场景

IK分词器

是一个中文分词器

  • 下载安装

  • 测试

    IK提供了两个分词算法ik_smart 和 ik_max_word,其中 ik_smart 为最少切分,ik_max_word为最细粒度划分

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
POST _analyze
{
"analyzer": "ik_smart",
"text":"php是世界上最好的语言吗?"
}
// php 是 世界上 最好 的 语言 吗

POST _analyze
{
"analyzer": "ik_max_word",
"text":"php是世界上最好的语言吗?"
}
// php 是 世界上 世界 上 最好 的 语言 吗

Mapping

定义数据库中的表的结构的定义,通过mapping来控制索引存储数据的设置

  • 获取索引mapping
Code
1
GET /atguigu/_mapping

响应:

Code
1
2
3
4
5
6
7
8
9
10
11
12
...
"properties": { #字段属性
"clazz": {
"type": "text", #字段类型,字符串默认类型
"fields": { #子字段属性设置
"keyword": { #分词类型(不分词)
"type": "keyword",
"ignore_above": 256
}
}
},
...
  • 自定义mapping

    Code
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    PUT my_index								#索引名称
    {
    "mappings":{
    "doc":{ #类型名称
    "dynamic":false,
    "properties":{
    "title":{
    "type":"text" #字段类型
    },
    "name":{
    "type":"keyword"
    },
    "age":{
    "type":"integer"
    }
    }
    }
    }
    }
  • dynamic设置

​ true:允许自动新增字段(默认的配置)

​ False:不允许自动新增字段,但是文档可以正常写入,无法对字段进行查询操作

​ strict:文档不能写入(如果写入会报错)

  • 支持的类型

数据类型

文档操作

CRUD

  • 创建文档

    1、索引一个文档

    2、使用自己的ID

    3、自增ID

  • 获取文档

    1、检索文档

    2、pretty

    3、检索文档的一部分

    Code
    1
    GET /website/blog/123?_source=title,text
  • 更新

  • 删除文档

    Code
    1
    DELETE /website/blog/123
  • 局部更新

  • 批量插入

    Code
    1
    2
    POST test_search_index/doc/_bulk
    {}
  • 检索多个文档

    Code
    1
    2
    POST /_mget
    {}

Search API(URI)

  • 查询案例

    1、批量创建文档

    Code
    1
    2
    3
    4
    5
    6
    7
    8
    9
    POST test_search_index/doc/_bulk
    {"index":{"_id":1}}
    {"username":"alfred way","job":"java engineer","age":18,"birth":"1991-12-15","isMarried":false}
    {"index":{"_id":2}}
    {"username":"alfred","job":"java senior engineer and java specialist","age":28, "birth":"1980-05-07", "isMarried":true}
    {"index":{"_id":3}}
    {"username":"lee", "job":"java and ruby engineer","age":22,"birth":"1985-08-07","isMarried":false}
    {"index":{"_id":4}}
    { "username":"lee junior way", "job":"ruby engineer","age":23, "birth":"1986-08-07","isMarried":false}

    2、泛查询

    3、查询语句执行计划查看

    4、term查询

    5、phrase查询

    6、group查询

    7、布尔操作符

  • Match Query

    对字段作全文检索,最基本和常用的查询类型。通过operator参数可以控制单词间的匹配关系,可选项为or和and

    Code
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    GET test_search_index/_search
    {
    "query":{
    "match": {
    "username": {
    "query":"alfred way",
    "operator":"and"
    }
    }
    }
    }

Elasticsearch集群

ElasticSerach集群安装

克隆虚拟机、改hostname、改ip地址、重启网络、修改配置文件。

注意:清空data和logs数据

安装集群监控

解压cerebro-0.8.1.tgz,运行bin/cerebro即可,访问elk111:9000

输入任意一个elk的地址:

Code
1
http://192.168.1.111:9200

就可以进入集群监控页。

集群简介

集群节点

集群健康

颜色 意义
green 所有主要分片和复制分片都可用
yellow 所有主要分片可用,但不是所有复制分片都可用
red 不是所有的主要分片都可用

集群分片

主分片:负载

副本分片:高可用

故障转移

集群操作原理

路由

操作数据节点工作流程

检索流程

Logstash

logstsh架构

logstash安装

logstsh input插件

  • Stdin

  • file

  • Elasticsearch

    Code
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    input {
    elasticsearch {
    hosts => "192.168.1.111"
    index => "mxx"
    query => '{ "query": { "match_all": {} }}'
    }
    }

    output {
    stdout {
    codec => "rubydebug"
    }
    }

logstsh filter

Filter是logstsh功能强大的原因,它可以对数据进行丰富的处理,比如解析数据、删除字段、类型转换等

date:日期解析

grok:正则匹配解析

dissect:分割符解析

mutate:对字段作处理,比如重命名、删除、替换等

json:按照json解析字段内容到指定字段中

geoip:增加地理位置数据

ruby:利用ruby代码来动态修改logstsh Event

Kibana

Code
1
2
3
4
5
6
7
8
9
10
11
12
vim kibana.yml

server.port: 5601
server.host: "192.168.1.111"
elasticsearch.url: "http://192.168.1.111:9200"
kibana.index: ".kibana"


# 运行
./kibana
# 访问
http://192.168.1.111:5601/

综合应用:每日访问量统计

logstash搜集nginx产生的日志,转化为json,存到es里了,最后使用kibana分析生成图表。

1、在elk111上装tomcat,放一个项目到webapps,测试能访问成功

2、安装nginx,修改配置文件,代理tomcat的项目,浏览器访问nginx代理,测试成功。

Code
1
2
3
4
location / {
proxy_pass http://manager/blog/;
proxy_redirect off;
}

3、刷新页面,用tail监控日志文件,发现日志数据一直在变化。

Code
1
tail -f /var/log/nginx/access.log

4、编辑logstash脚本

Code
1
2
3
输入:监控nginx日志文件access.log
过滤:正则匹配,一些参数...
输出:控制台,es(使用时间做索引,每天生产一1个索引)

日志数据格式:

Code
1
192.168.1.5 - - [27/Dec/2019:19:07:18 +0800] "GET /blog/css/main.css?v=6.4.2 HTTP/1.1" 404 995 "http://elk111/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36"

过滤正则:

Code
1
2
3
4
5
/home/machine/logstash/job/patterns/
vim nginx

NGINXACCESS %{IPORHOST:clientip} %{HTTPDUSER:ident} %{USER:auth} \[%{HTTPDATE:timestamp}\] "(?:%{WORD:verb} %{NOTSPACE:request}(?: HTTP/%{NUMBER:httpversion})?|%{DATA:rowrequest})" %{NUMBER:response} (?:%{NUMBER:bytes}|-)
NGINXACCESSLOG %{COMMONAPACHELOG} %{QS:referrer} %{QS:agent}

logstash脚本

Code
1
2
/home/machine/logstash/job
vim nginx_logstash.conf

nginx_logstash.conf

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
input {
file {
path => ["/var/log/nginx/access.log"]
type => "nginx_access"
#start_position => "beginning"
}
}
filter {
if [type] == "nginx_access" {
grok {
patterns_dir => "/home/machine/logstash/job/patterns/"
match => {
"message" => "%{NGINXACCESS}"
}
}

date {
match => ["timestamp","dd/MMM/YYY:HH:mm:ss Z"]
}

if [param] {
ruby {
init => "@kname = ['quote','url_args']"
code => "
new_event =
LogStash::Event.new(Hash[@kname.zip(event.get('param').split('?'))])
new_event.remove('@timestamp')
event.append(new_event)
"
}
}

if [url_args] {
ruby {
init => "@kname = ['key','value']"
code => "event.set('nested_args',event.get('url_args').split('&').cllect{|i| Hash[@kname.zip(i.split('='))]})"
remove_field => ["url_args","param","quote"]
}
}

mutate {
convert => ["response","integer"]
remove_field => "timestamp"
}
}
}
output {
stdout {
codec => rubydebug
}

elasticsearch {
hosts => ["http://192.168.1.111:9200"]
index => "logstash-%{type}-%{+YYYY.MM.dd}"
}
}

5、执行写好的logstash脚本,进行监控。刷新页面,看控制台效果

Code
1
bin/logstash -f /home/machine/logstash/job/nginx_logstash.conf

6、使用Kibana在Management那创建一个 index pattern,名字:logstash* (匹配所有的日志数据索引)

​ 按时间戳进行匹配

7、查一下某个索引的数据是否存在,刷新页面,看是否实时增加了

Code
1
2
3
4
5
6
GET logstash-nginx_access-2019.12.27/_search
{
"query": {
"match_all": {}
}
}

8、创建图表,选择logstash*的索引

Code
1
2
3
Y count
X Date Histogram
filed @timestamp

9、生成图表,可以save保存图表。

image-20191227195133398
文章作者: Machine
文章链接: https://machine4869.gitee.io/2019/12/26/20191226144408846/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 哑舍
打赏
  • 微信
    微信
  • 支付宝
    支付宝

评论