ELK

ELK=Elasticsearch+Logstash+Kibana

ElasticSearch:实时的分布式搜索和分析引擎,与Solr类似;他可以近乎实时的存储和检索数据;建立在Apache Lucene基础上的搜索引擎,使用java语言编写

Elasticsearch特点:

1.实时分析

2.分布式实时文件存储,并将每一个字段都编入索引

3.文档导向,所有的对象全部都是文档

4.高可用,易扩展,支持集群,分片和复制

5.接口优化,支持json

 Logstash:类似于Flume,做数据采集的框架

Logstash特点:

1.几乎可以访问任何数据

2.可以和多种外部应用结合

3.支持弹性扩展

它由三个主要部分组成

1.Shipper-发送日志数据

2.Broker-收集数据,缺省内置 Redis

Indexer-数据写入

Kibana:数据报表展示

三个框架,基本上就可以形成一个一站式的解决方案;

ElasticSearch:

实时的分布式搜索和分析引擎,与Solr类似;他可以近乎实时的存储和检索数据;

ElasticSearch对比Solr

•Solr 利用 Zookeeper 进行分布式管理,而 Elasticsearch 自身带有分布式协调管理功能;

•Solr 支持更多格式的数据,而 Elasticsearch 仅支持json文件格式;

•Solr 官方提供的功能更多,而 Elasticsearch 本身更注重于核心功能,高级功能多有第三方插件提供;

•Solr 在传统的搜索应用中表现好于 Elasticsearch,但在处理实时搜索应用时效率明显低于 Elasticsearch

 ES架构

插入数据保存到ES中,类似数据库;首先要知道是哪个数据库,哪个表先指定插入到ES索引库(Index),还有指定ES索引库下的那张表(Types);之后将数据进行分片(Shard)存储到集群上去,通过hash取值将分片的数据存储到集群(每条数据系统都会分配id,id对节点个数进行hash取值),最后进行副本机制存储

 

我们插入的数据可能包含多个字段;ES当中的一个个字段,叫做一个个Field

要将数据保存到节点上要设置:

mappings:主要用于我们的字段定义类型,以及分词,以及存储的特性

  • 存不存储:在ES当中存储,就可以查询出来展示
  • 分布分词:如果分词,我们就可以通过词语进行查找
  • 索不索引:如果索引就可以进行查找,如果不索引,我们就没办法索引

settings:主要用于设置ES索引库的分片数和副本数

 

ES可以看做一个数据库来学:

Index索引库-->Types类似一张张表-->field字段

mysql数据库-->table-->column字段

mappings:定义es当中的字段的类型,以及分词、存储、索引的特性

setting:主要用于设置es索引库的分片数和副本数

ducument:就是一个个的json字符串,es当中所有的数据都是json字符串

接近实时NRT:搜索速度快(延时通常是1秒以内)

cluster:ES本身就是分布式,一个集群由一个或多个节点组成

node:一个节点是集群中的一个服务器,作为集群的一部分,它存储数据,参与集群的索引和搜索功能。

shards:1)允许你水平分割/扩展你的内容容量。 2)允许你在分片(潜在地,位于多个节点上)之上进行分布式的、并行的操作,进而提高性能/吞吐量。

replicas:在分片/节点失败的情况下,提供了高可用性。

elasticsearch-head:

这个插件是es提供的一个用于图形化界面查看的一个插件工具,可以安装上这个插件之后,通过这个插件来实现我们通过浏览器查看es当中的数据

es-head插件的安装:使用js来开发,需要使用js来操作es的后台数据

js能不能够操作后台的文件

规定:js不能操作任何的文件,只是一个浏览器端的语言

js是通过一个平台包装起来了,运行在一个nodejs的平台上面,才可以去后台执行各种操作

es-head插件可以用来管理集群,包括索引库数据的查询,但是没有添加索引数据,删除索引数据的操作

kibana:数据展示的框架,同时可以通过我们的curl的命令来执行我们的es数据操作,包括增删改查

curl-XPUT http://node01:9200/blog01/?pretty

curl--是kibana常用的命令,发送请求的命令
XPUT--创建一个索引库
blog01--索引库的名字
pretty--格式化,

 

默认创建blog01索引库,是包含5个分片和2个副本

 索引管理

插入数据

curl -XPUT http://node01:9200/blog01/article/1?pretty -d  '{"id": "1", "title": "What is lucene"}' blog01--索引库 article--表 1--表示数据的id,系统默认的id

 

 

linux上插入数据

curl -XPUT http://node01:9200/blog01/article/1?pretty -d \  '{"id": "1", "title": "What is lucene"}' \ -H "Content-Type: application/json"

 

必须条件-H "Content-Type: application/json";此原因时由于ES增加了安全机制, 进行严格的内容类型检查,严格检查内容类型也可以作为防止跨站点请求伪造攻击的一层保护。

 

查询数据

curl -XGET http://node01:9200/blog01/article/1?pretty

 

 

更新文档

curl -XPUT http://node01:9200/blog01/article/1?pretty -d  \
 '{"id": "1", "title": " What is elasticsearch"}'

 

更新数据其实就是插入数据,当系统id相同时,添加数据就是更新数

 

搜索文档

curl -XGET "http://node01:9200/blog01/article/_search?q=title:elasticsearch&pretty" 
_search表示搜索 
查询结果: 
    took:表示获取数据的时间 
    hits:表示获取多少数据,所有数据都包含在里面的hits里面

 

 

删除文档

curl -XDELETE "http://node01:9200/blog01/article/1?pretty"

 

 

删除索引

curl -XDELETE http://node01:9200/blog01?pretty

 

 

ES查询

批量添加数据

例如:

POST /school/student/_bulk

往school索引库,student表,批量添加数据

 

 

1.match_all做查询

匹配所有

 

GET /school/student/_search?pretty
{
    "query": {
        "match_all": {}
    }
}

 

 

 

 

 

2.通过关键字段进行查询

查询含有"travel"字段的

GET /school/student/_search?pretty
{
    "query": {
         "match": {"about": "travel"}
     }
}

 

 

3.bool的复合查询

查询喜欢旅游且不是男孩的数据

GET /school/student/_search?pretty
{
"query": {
   "bool": {
      "must": { "match": {"about": "travel"}},
      "must_not": {"match": {"sex": "boy"}}
     }
  }
}

 

 

4.bool的复合查询中的should

should表示可有可无的(如果should匹配到了就展示,否则就不展示)

例子:

查询喜欢旅行的,如果有男性的则显示,否则不显示

GET /school/student/_search?pretty
{
"query": {
   "bool": {
      "must": { "match": {"about": "travel"}},
      "should": {"match": {"sex": "boy"}}         
     }
  }
}

 

 

5.term匹配

使用term进行精确匹配(比如数字,日期,布尔值或 not_analyzed的字符串(未经分析的文本数据类型))

语法

{ "term": { "age": 20 }}

{ "term": { "date": "2018-04-01" }}

{ "term": { "sex": “boy” }}

{ "term": { "about": "trivel" }}

例子:

查询喜欢旅行的

GET /school/student/_search?pretty
{
"query": {
   "bool": {
      "must": { "term": {"about": "travel"}},
      "should": {"term": {"sex": "boy"}}         
     }
  }
}

 

 

6.使用terms匹配多个值

GET /school/student/_search?pretty
{
"query": {
   "bool": {
      "must": { "terms": {"about": ["travel","history"]}}          
     }
  }
}

term主要是用于精确的过滤比如说:”我爱你”

在match下面匹配可以为包含:我、爱、你、我爱等等的解析器

在term语法下面就精准匹配到:”我爱你”

 

7.Range过滤

Range过滤允许我们按照指定的范围查找一些数据:操作范围:gt::大于,gae::大于等于,lt::小于,lte::小于等于

例子:

查找出大于20岁,小于等于25岁的学生

GET /school/student/_search?pretty
{
"query": {
   "range": {
    "age": {"gt":20,"lte":25}
         }
      }
}

 

 

8.exists和 missing过滤

exists和missing过滤可以找到文档中是否包含某个字段或者是没有某个字段

exists:包含某个字段必须展示

missing:过滤掉某个字段,不进行展示

例子:

查找字段中包含age的文档

GET /school/student/_search?pretty
{
"query": {
   "exists": {
    "field": "age"  
         }
      }
}

 

 

9.bool的多条件过滤

用bool也可以像之前match一样来过滤多行条件:

must :: 多个查询条件的完全匹配,相当于 and 。

must_not :: 多个查询条件的相反匹配,相当于 not 。

should :: 至少有一个查询条件匹配, 相当于 or

例子:

过滤出about字段包含travel并且年龄大于20岁小于30岁的同学

GET /school/student/_search?pretty
{
  "query": {
    "bool": {
      "must": [
        {"term": {
          "about": {
            "value": "travel"
          }
        }},{"range": {
          "age": {
            "gte": 20,
            "lte": 30
          }
        }}
      ]
    }
  }
}

 

 

10.查询与过滤条件合并

通常复杂的查询语句,我们也要配合过滤语句来实现缓存,用filter语句就可以来实现

例子:

查询出喜欢旅行的,并且年龄是20岁的文档

GET /school/student/_search?pretty
{
  "query": {
   "bool": {
     "must": {"match": {"about": "travel"}},     
     "filter": [{"term":{"age": 20}}]
     }
  }
} 

 

 

索引映射(mappings)管理

我们说ES可以看做成为一个数据,往数据库里面添加数据时要提前定义好字段类型

mappings就是定义数据字段的类型,当我们是put的方式插入数据时,

比如:id字段类型是int,但是插入的数据时"abc"则无法插入数据,如果插入的"123",则可以通过自动转换,转换成为int类型进行插入

 

其实添加数据时,最好带上字段类型

DELETE school
PUT school
{
  "mappings": {
    "logs" : {
      "properties": {"messages" : {"type": "text"}}
    }
  }
}
添加索引:school,文档类型类logs,索引字段为message ,字段的类型为text

 

 

添加字段类型的好处:

PUT /document/article/1
{
  "author" : "zhangsan",
  "titleScore" : 60
}

查看索引字段类型:GET /document/article/_mapping。可以发现titleScore的类型是long。

 

PUT /document/article/2
{
  "title" : "elasticsearchshi是是什么",
  "author" : "zhangsan",
  "titleScore" : 66.666
}

查看索引字段类型:GET /document/article/_mapping。可以发现titleScore的类型是long。

 

问题:如果后期ElaticSearch对接java的时候,将会把titleScore类型定义为Long类型

class Article{

private String title;

private String author;

private Long titleScore

titleScore的值,将会变为66;精度将会改变

 

 

为了解决后期我们查询时候造成数据的精度丢失,我们可提前通过mappings定义好我们每一个字段类型,不会造成精度丢失的问题

 

索引库(setting)的设置

settings用于设置es索引库的分片数,副本数

 

可以更改索引库的副本

但是分片数是在索引库创建的时候指定的,一旦指定分片数就没有办法更改

如果数量较大,查询比较频繁,分片数量尽可能创建多一点,一般分片数都是服务器个数的N倍

PUT document
{
  "mappings": {
    "article" : {
      "properties":
      {
        "title" : {"type": "text"} , 
        "author" : {"type": "text"} , 
        "titleScore" : {"type": "double"} 
        
      }
    }
  }
}

 

 

查看settings

GET /document/_settings

 

 

修改settings

可以看到当前的副本数是1,那么为了提高容错性,我们可以把副本数改成2:
PUT /document/_settings
{
  "number_of_replicas": 2
}

 

 

package com.tainjp.es;

import com.alibaba.fastjson.JSONObject;
import org.elasticsearch.action.index.IndexRequestBuilder;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashMap;

/**
 * @author Tianjinpen
 * @Create 2020-03-22 16:45
 */
public class ES01 {

    TransportClient client=null;

    //1.创建索引库,通过客户端连接服务端,所以创建客户端
    //获取es客户端
    @Before
    public void initClient() throws UnknownHostException {
        //获取settings对象
        //put方法设置es参数属性
        Settings settings = Settings.builder().put().build();

        //2.客户端需要连接服务端
        TransportAddress transportAddress1 = new TransportAddress(InetAddress.getByName("192.168.56.100"), 9300);
        TransportAddress transportAddress2 = new TransportAddress(InetAddress.getByName("192.168.58.110"), 9300);
        TransportAddress transportAddress3 = new TransportAddress(InetAddress.getByName("192.168.58.120"), 9300);
        //配置构造参数
        client = new PreBuiltTransportClient(settings).addTransportAddress(transportAddress1).addTransportAddress(transportAddress2).addTransportAddress(transportAddress3);
    }

    /*向索引库中添加索引
    *一共四种方式
    * */


    @Test
    //第一种方式:通过json的方式
    public void createIndex1(){

        String json = "{" +
                "\"user\":\"kimchy\"," +
                "\"postDate\":\"2013-01-30\"," +
                "\"message\":\"travelying out Elasticsearch\"" +
                "}";

        IndexRequestBuilder indexRequestBuilder = client.prepareIndex("myIndex1", "article", "1");
        IndexResponse indexResponse = indexRequestBuilder.setSource(json, XContentType.JSON).get();
    }

    @Test
    //第二种方式:通过mapping的方式
    public void createIndex2(){
        HashMap<String, String> jsonMap = new HashMap<String, String>();
        jsonMap.put("name", "zhangsan");
        jsonMap.put("sex", "1");
        jsonMap.put("age", "18");
        jsonMap.put("address", "bj");

        IndexRequestBuilder indexRequestBuilder = client.prepareIndex("myIndex1", "article", "2");
        IndexResponse indexResponse = indexRequestBuilder.setSource(jsonMap).get();
    }

    @Test
    //第三种方式:XcontentType的方式
    public void createIndex3() throws IOException {
        IndexResponse indexResponse = client.prepareIndex("myindex1", "article", "3")
                .setSource(new XContentFactory().jsonBuilder()
                        .startObject()
                        .field("name", "lisi")
                        .field("age", "18")
                        .field("sex", "0")
                        .field("address", "bj")
                        .endObject())
                .get();
    }

    @Test
    //第四种方式:Java对象转接送
    public void createIndex4(){
        Person person = new Person();
        person.setAge(18);
        person.setId(20);
        person.setName("张三丰");
        person.setAddress("武当山");
        person.setEmail("zhangsanfeng@163.com");
        person.setPhone("18588888888");
        person.setSex(1);
        String json = JSONObject.toJSONString(person);

        client.prepareIndex("myindex1", "article", "4").setSource(json,XContentType.JSON).get();
    }

    @After
    public void closeClient(){
        client.close();
    }
}

 

 

 

 

 

 

 

 

 

 

posted @ 2020-03-22 20:30  IT界一个小学生  阅读(340)  评论(0编辑  收藏  举报