前两篇笔记里面写了ELK的安装ES的scroll查询与分片查询,关于查询的一些其他知识点以及我刚接触ELK的时候遇到的一些问题,准备在下面稍稍带过一下。

查询相关的内容

ES里面存储的可以认为是文档,它搜索的时候其实是“模糊查询”。

 GET parsed-nginx-access-log/_search
{
  "query": {
    "match_all": {}
  }
}

ES默认返回了10条记过,选择其中一条拿出来看

    {
        "_index": "parsed-nginx-access-log",
        "_type": "doc",
        "_id": "u3WFzGIBS0ZNO-1q5iBf",
        "_score": 1,
        "_source": {
          "host": "localhost",
          "@timestamp": "2018-04-16T03:35:48.199Z",
          "request": "/elasticsearch/_msearch",
          "request_time": 0.066,
          "@version": "1",
          "http_version": "1.1",
          "body_bytes_sent": "5794",
          "method": "POST",
          "status": "200",
          "upstream_response_time": 0.067,
          "path": "/usr/local/nginx/logs/access.log"
        }
    }

查询字符串

例如说,我有个需求,我想找request字段是/elasticsearch/的文档,用下面这个查询语句

GET parsed-nginx-access-log/_search
{
  "query": {
    "match": {
      "request" : "/elasticsearch/"
    }
  }
}

结果"request": "/elasticsearch/_msearch"这种文档也会被返回给我。

原来是我用错了,我要的是精确查询。

精确查询

字符串也是可以精确查询的,比如说用下面这个查询语句

GET parsed-nginx-access-log/_search
{
  "query": {
    "match": {
      "request.keyword" : "/elasticsearch/"
    }
  }
}

ES 2.x的时候,只有string字段。从ES 5.X起,string字段变成过时字段,引入了text和keyword字段。

  • keyword存储数据的时候,不会分词。
  • text存储数据的时候,会自动分词。

当我进行精确查询的时候,我其实是不需要打分的,我就可以用constant_score来以非评分模式查询

GET parsed-nginx-access-log/_search
{
    "query" : {
        "constant_score" : { 
            "filter" : {
                "term" : { 
                    "request.keyword" : "/elasticsearch/"
                }
            }
        }
    }
}

组合查询

上面只查询一个字段,如果要同时符合多个条件,就要用到组合查询。

比如说,我想要查询request/elasticsearch/并且status200的所有记录,我不需要评分, 可以使用下面这个查询语句

GET parsed-nginx-access-log/_search
{
    "query": {
      "constant_score" : {
        "filter" : {
            "bool" : {
                "must" : [
                        { "term" : { "status.keyword" : "200"  } },
                        { "term" : { "request.keyword" : "/elasticsearch/" } }
                    ]
                }
            }
      }
    }
}

自定义logstash模板

看到上面查询status的时候,它是一个字符串类型。我想让它存在ES里面的时候是个int类型,那么在logstash对文档进行正则匹配的时候,就可以对字段类型进行设置。

grok 表达式的打印复制格式的完整语法是%{PATTERN_NAME:capture_name:data_type},其中data_type只能是int或者float

比如说你想要status字段是int类型,那么对于这个字段的匹配就可以是这样的%{INT:status:int}

你可以使用Grok Debugger来调试自己的grok表达式,而这个链接里面是grok预定义好的一些正则表达式


使用过程中遇到的问题

问题1:logstash不读取最后一条日志

我测试的时候,用了一个只有5条日志的文件,然后使用logstash进行匹配。我发现最后一条日志,没有被写到ES里面。

然后在官网上找到了它的解释,如下图:

不读取最后一条记录

问题2:FATAL Port 5601 is already in use. Another instance of Kibana may be running!

我一般都在终端里面运行kibana,并没有把它nohup放到后台。有时候终端会断开连接,导致kibana还在运行,所以不能再启动kibana。

解决办法就是,运行命令lsof -i :5601,然后kill掉。之后就能够再重启了

问题3:LogStash抓取一遍的日志内容就不会重新抓取了

LogStash会用一个数据库(sincedb)存储监控的日志文件的读取记录,所以,如果日志文件没有更新的话,Logstash也就不会再读取。

这个sincedb数据库的路径默认在logstash/data/plugins/inputs/file/文件夹里面

所以如果在调试的时候,你希望Logstash反复抓取同一个日志文件,可以这样做:

  • 方法一:人工删除sincedb文件
  • 方法而:在logstash的配置文件里面强制设置sincedb_path参数到/dev/null,这个方案对于配置文件具有侵入性。

我个人还是建议在测试的时候使用第一种方法。如果使用第二种,万一忘记把配置文件改回来,就放到线上去,这就不太好了。