ELK入门

ELK = Elasticsearch + Logstash + Kibana。

  • Elasticsearch :一个搜索和分析引擎
  • Logstash:服务器端数据处理管道,能够同时从多个来源采集数据,转换数据,然后将数据发送到诸如 Elasticsearch 等“存储库”中
  • Kibana :使用户在 Elasticsearch 中使用图形和图表对数据进行可视化。

一、 安装

1. ElasticSearch

很不错的安装教程
启动:

  1. ElasticSearch的bin目录下bat文件启动ES
  2. elasticsearch-head-master目录下,命令行输入grunt server启动head插件
  3. http://localhost:9100/ 在head下查看当前集群

2. Kibana

下载地址
这里我下载的是6.2.4版本,和ES版本一致

若本机已经安装并启动elasticsearch,则kibana会默认连接localhost:9200端口的elasticsearch
打开浏览器输入: http://localhost:5601/,就可以看到kibana的控制后台。

kibana配置修改:
config/kibana.yml
在这里插入图片描述
注意配置文件中对应的端口号(9200),连接哪个es配置哪个。.bat文件启动。

3. logstash

下载地址
同样是6.2.4版本

二、使用

1. logstash使用

ES可以通过JAVA API等方式将数据写入节点,但是使用logstash更快更方便。
入门大致格式参考:logstash从csv文件导入数据到elasticsearch
logstash启动:bin目录下logstash -f logstash.conf启动(logstash.conf为写好的配置文件)

这里在启动logstash时遇到一个问题:输入logstash -f logstash.conf后报找不到或无法加载主类。解决方法参考

模板使用

logstash向ES中写入数据时,如果对数据格式等有要求,要先定义模板。
例如我在开始时遇到的问题是,默认的模板对数据自动进行分词,而我本来不需要这种分词,那么就需要重新定义自己的模板。
这里推荐两篇文章,可以参考:

2. ElasticSearch使用

这里主要使用JAVA API来对ES操作,主要介绍JAVA API的方法,也可以使用Restful的方法。

(1)创建索引库

    private TransportClient client;

    @Before //表示在任意使用@Test注解标注的public void方法执行之前执行
    //创建client对象
    public void init() throws Exception{
        //1.创建一个Settings对象,相当于是一个配置信息,主要配置集群的名称
        Settings settings= Settings.builder().put("cluster.name","my-application").build();

        //2.创建一个客户端client对象
        client=new PreBuiltTransportClient(settings);
        client.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"),9300));
    }

    /*
    1. 创建索引库
     */
    @Test
    public void createIndex() throws Exception{
        long startTime = System.currentTimeMillis();
        init();

        //3.使用client对象创建一个索引
        client.admin().indices().prepareCreate("IndexName")
                //执行操作
                .get();
        long createIndexTime = System.currentTimeMillis() - startTime;
        System.out.println("创建索引的时间:"+createIndexTime);

        //4.关闭client对象
        client.close();
    }

除了使用logstash定义mapping和上传数据的方法外,ES也可以自己通过JAVA API完成。(但是个人认为很麻烦,实际中没有使用)

	/*
    2.使用Java客户端设置Mappings
     */
    @Test
    public void setMappings() throws Exception{
        init();
        //3.创建一个mappings信息
        XContentBuilder builder= XContentFactory.jsonBuilder()
                .startObject() //开头的{
                    .startObject("article")
                        .startObject("properties")
                            .startObject("id")
                                .field("type","long")
                                .field("store",true)
                            .endObject()
                            .startObject("title")
                                .field("type","text")
                                .field("store",true)
                                .field("analyzer","ik_smart")
                            .endObject()
                            .startObject("content")
                                .field("type","text")
                                .field("store",true)
                                .field("analyzer","ik_smart")
                            .endObject()
                        .endObject()
                    .endObject()
                .endObject();
        //4.使用client把mapping信息设置到索引库中
        client.admin().indices()
                //设置要做映射的索引
                .preparePutMapping("IndexName")
                //设置要做映射的type
                .setType("article")
                //mapping信息,可以是XContextBuilder对象可以是json格式字符串
                .setSource(builder)
                //执行操作
                .get();
        //5.关闭连接
        client.close();
    }

    /*
    3.1. 添加文档(XContentBuilder)
     */
    @Test
    public void testAddDocument() throws Exception{
        //3.创建一个文档对象
        XContentBuilder builder = XContentFactory.jsonBuilder()
                .startObject()
                    .field("id",1l)
                    .field("title","开开心心")
                    .field("content","今天也要加油鸭")
                .endObject();
        //4.把文档对象添加到索引库
        //client.prepareIndex("IndexName","article","1");
        client.prepareIndex()
                //设置索引名称
                .setIndex("IndexName")
                //设置type
                .setType("article")
                //设置文档id,如果不设置会自动生成一个id
                .setId("1")
                //设置文档信息
                .setSource(builder)
                //执行操作
                .get();
        //5.关闭客户端
        client.close();
    }

    /*
    3.2. 添加文档(Jackson)
     */
    @Test
    public void testAddDocument2() throws Exception{
        //创建article对象(创建一个pojo类)
        Article article=new Article();
        //设置对象属性
        article.setId(3l);
        article.setTitle("星期一");
        article.setContent("又是没有好好减肥的一天");
        //把article对象转换成json格式的字符串(使用工具类)
        ObjectMapper objectMapper=new ObjectMapper();
        String jsonDoc=objectMapper.writeValueAsString(article);
        System.out.println(jsonDoc);
        //使用client对象,把文档写入索引库
        client.prepareIndex("IndexName","article","3")
                .setSource(jsonDoc, XContentType.JSON)
                .get();
        //关闭客户端
        client.close();
    }

(2)查询

查询设置

		private TransportClient client;
		//查询设置
		long startTime = System.currentTimeMillis();
        SearchRequestBuilder srb=client.prepareSearch("healthapp_index");
        QueryBuilder queryBuilder0= QueryBuilders.matchPhraseQuery("logKey",3);
        QueryBuilder queryBuilder1=QueryBuilders.matchPhraseQuery("logKey",4);

执行查询

PUT _settings
{
    "index": {
        "max_result_window": "10000000"
    }
}
SearchResponse sr = srb.setQuery(QueryBuilders.boolQuery()
                .should(queryBuilder0)
                .should(queryBuilder1)
        )
                .setFrom(0).setSize(260000)
                .get();

查询中产生的问题及解决方法:

  1. 分页查询(from+size)
    这里使用from和size进行分页查询:
    from表示从第几行开始,size表示查询多少条文档。
    from默认为0,size默认为10, 如果搜索size大于10000,需要设置index.max_result_window参数
    注意:size的大小不能超过index.max_result_window这个参数的设置,默认为10,000。
    这里设置成了260000,所以需要先修改该参数
    可以在Kibina中修改
    参考

  2. TooManyClauses问题 如果bool查询的查询条件过多会导致TooManyClauses问题。

    “caused_by”:{“type”:“too_many_clauses”,“reason”:“maxClauseCount is set to 1024”}

    解决方式: 配置文件 Elasticsearch.yuml中配置 index.query.bool.max_clause_count:10240
    5+版本配置: indices.query.bool.max_clause_count: 10240
    设置最大限制bool查询的条数。过多会导致性能比较慢

  3. 分页查询之滚动查询
    优点:当结果足够大的时候, scroll 性能更好。
    缺点:但是不灵活和 scroll_id 难管理问题存在
    方法参考:
    Elasticsearch使用scroll进行分页查询
    注意
    1)第一次设置scrollId以后,要先执行一次才能获得现有的ID中滚动到的值。参考:[ElasticSearch]Java API 之 滚动搜索(Scroll API)
    2)滚动时长的设置不要太短。
    这里附上博主自己的实际使用:

        //查询设置
        long startTime = System.currentTimeMillis();
        SearchRequestBuilder srb=client.prepareSearch("hdfs_es")
                .setTypes("hdfs");
        QueryBuilder queryBuilder0= QueryBuilders.termQuery("logKey",2);
        QueryBuilder queryBuilder1=QueryBuilders.termQuery("logKey",3);

        SearchResponse sr = srb.setQuery(queryBuilder0)
                .setSize(50000).setScroll(new TimeValue(100000))
                .get();
        long totalCount=sr.getHits().getTotalHits();
        int page=(int)totalCount/50000;
        System.out.println("查询结果总记录数:" + totalCount);

        SearchHits hits=sr.getHits();
        for (SearchHit searchHit:hits) {
            String[] outcsvline=new String[head1.length + head2.size()];
            Map<String, Object> document = searchHit.getSource();

            int logkey=Integer.parseInt(document.get("logKey").toString());
            outcsvline[0] = document.get("logKey").toString();
            outcsvline[1] = document.get("timeStamp").toString();
            outcsvline[2] = document.get("Component").toString();
            outcsvline[3] = document.get("Pid").toString();
            outcsvline[4] = document.get("EventTemplate").toString();
            outcsvline[5] = document.get("Level").toString();
            int add = 0;
            for (int kk = 0; kk < logkey; kk++) {
                add += logkeycnt[kk];
            }
            for (int j = 0; j< logkeycnt[logkey]; j++) {
                String tmp = (logkey + "") + "_ParameterList" + (j + "");
                try {
                    outcsvline[6 + add + j] = document.get(tmp).toString();
                } catch (Exception e) {
                    continue;
                }
            }
            csvWriter.writeRecord(outcsvline);
        }
        for(int i=0;i<=page;i++){
            sr = client.prepareSearchScroll(sr.getScrollId())
                    .setScroll(new TimeValue(100000))
                    .get();
            hits=sr.getHits();
            for (SearchHit searchHit:hits) {
                String[] outcsvline=new String[head1.length + head2.size()];
                Map<String, Object> document = searchHit.getSource();

                int logkey=Integer.parseInt(document.get("logKey").toString());
                outcsvline[0] = document.get("logKey").toString();
                outcsvline[1] = document.get("timeStamp").toString();
                outcsvline[2] = document.get("Component").toString();
                outcsvline[3] = document.get("Pid").toString();
                outcsvline[4] = document.get("EventTemplate").toString();
                outcsvline[5] = document.get("Level").toString();
                int add = 0;
                for (int kk = 0; kk < logkey; kk++) {
                    add += logkeycnt[kk];
                }
                for (int j = 0; j< logkeycnt[logkey]; j++) {
                    String tmp = (logkey + "") + "_ParameterList" + (j + "");
                    try {
                        outcsvline[6 + add + j] = document.get(tmp).toString();
                    } catch (Exception e) {
                        continue;
                    }
                }
                csvWriter.writeRecord(outcsvline);
            }
        }

处理查询结果

        //取查询结果
        SearchHits searchHits = sr.getHits();
        //取查询结果的总记录数
        System.out.println("查询结果总记录数:" + searchHits.getTotalHits());
        for (SearchHit searchHit:searchHits) {
            String[] outcsvline=new String[head1.length + head2.size()];
            Map<String, Object> document = searchHit.getSource();

			//通过get方法取到ES结果中对应属性
            int logkey=Integer.parseInt(document.get("logKey").toString());
            outcsvline[0]=document.get("logKey").toString();
            outcsvline[1]=document.get("timeStamp").toString();
            outcsvline[2]=document.get("Component").toString();
            outcsvline[3]=document.get("Pid").toString();
            outcsvline[4]=document.get("EventTemplate").toString();
            int add=0;
            for(int kk=0;kk<logkey;kk++){
                add+=logkeycnt[kk];
            }
            for(int i=0;i<logkeycnt[logkey];i++){
                String tmp=(logkey+"")+"_ParameterList"+(i+"");
                try{
                    outcsvline[5+add+i]=document.get(tmp).toString();
                }catch (Exception e){
                    continue;
                }
            }
            csvWriter.writeRecord(outcsvline);
        }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值