日志平台总查不到日志,怎么办?运维大侠来支招~
笔者在一家银行科技部门工作。从2018年开始接触 Elasticsearch(以下简称ES),我所在的日志平台团队从ES5.x到ES7.x,对ES的两个大版本都经历了比较深入的实践。从初的日志检索,到后来的数据分析、智能监控,ES 在行内的应用越来越广泛。
1.ES全文搜索原理
1.1 倒排索引
一般而言,在数据库中直接全表查询的时间复杂度是 O(n),如果对索引列进行查询,其时间复杂度为O(logn),而数据以 key-value 的形式存储,查询时间复杂度将降为 O(1)。倒排索引则是在全文搜索中直接建立从查询词到文档的映射,从而将查询复杂度降到O(1),大大提高了查询性能。
1.2 数据索引写入过程
创建文档对象
分析文档
索引创建
将分析文档得到的一个个关键词传给索引组件。索引组件会根据这些词创建关键词与文档的映射关系,从而形成一个大的词典。词典的索引结构则是一种倒排索引结构,包括索引和文档两部分,索引即词汇表,它的规模较小,而文档集合规模较大。
1.3 数据查询过程
查询语句
执行搜索
根据得到的文档和查询语句的相关性,对结果进行排序。
1.4 分词
字符过滤器
<b>的字符从原始文本中剥离出去。标记器
标记过滤器
2.解决问题
2.1 写入分词优化
2.1.1 探索ES默认英文分词器
POST token_test_index-2021.05.26/_doc{ "message":"java.outofmemory"}
2、用 ES 默认分词器查看对 message 的分词情况。
POST token_test_index-2021.05.26/_analyze{ "analyzer":"standard", "text": "java.outofmemory"}
返回值为:
{ "tokens" : [ { "token" : "java.outofmemory", "start_offset" : , "end_offset" : 18, "type" : "<ALPHANUM>", "position" : } ]}
从中可以看出 java.outofmemory 被作为一个词存入了ES里。
用关键词 outofmemory 从 ES 中进行搜索。
{ "took" : 3, "timed_out" : false, "_shards" : { "total" : 3, "succESsful" : 3, "skipped" : , "failed" : }, "hits" : { "total" : { "value" : , "relation" : "eq" }, "max_score" : null, "hits" : [ ] }}
2.1.2 自定义英文分词器
默认分词器,不对以特殊字符“.”连接的词汇进行分词,然而很多系统打印的错误日志内容格式我们是无法提前知道的,只能通过关键词去搜索,分词的限制使得我们无法搜索到想要的结果。
通过对ES分词原理的了解,我们知道ES分词有字符过滤器,标记器和标记过滤器三部分。字符过滤器的作用是在一段文本进行分词之前,先进行预处理,将多余的字符去掉。在这里,我们尝试自定义一个字符过滤器,将不分词的特殊字符全部过滤掉。
my_analyzer1,并将其应用于 token_test_index-* 索引模板
PUT _template/token_tESt_index{ "order" : 10, "index_patterns" : [ "token_test_index-*" ], "settings":{ "refresh_interval" : "1s", "analysis": { "analyzer": { "my_analyzer1":{ "type": "custom", "char_filter": [ "special_char_filter" ], "tokenizer":"standard" } }, "char_filter":{ "special_char_filter":{ "type": "mapping", "mappings":[ "· => " ] } } } }, "mappings" : { "properties" : { "message" : { "type" : "text", "analyzer":"my_analyzer1", "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 256 } } } } }}
3.重新以outofmemory关键字搜索新建索引。
GET token_test_index-2021.05.26_1/_search{ "query": { "query_string": { "default_field": "message", "query": "outofmemory" } }}
返回结果如下:
{ "took" : 2, "timed_out" : false, "_shards" : { "total" : 3, "successful" : 3, "skipped" : , "failed" : }, "hits" : { "total" : { "value" : 2, "relation" : "eq" }, "max_score" : .8025915, "hits" : [ { "_index" : "token_test_index-2021.05.26", "_type" : "_doc", "_id" : "4CSDp3kBitgxHTbP_Efs", "_score" : .8025915, "_source" : { "message" : "java.outofmemory" } } ] }}
“:”,”.”,”‘“,”_”,”·”,”:”,”‘“,”’”。将这些特殊字符在字符过滤器阶段以空格替代的方式,可以很好解决该问题,并极大地提高关键词命中率。
2.2 查询分词优化
在查询上使用更加粗粒度的分词,有助于我们过滤掉大量不需要的结果,从而提高结果的命中率。英文分词可以直接通过空格、标点符号等停用词对其进行分词,这一点官网提供的分词插件已经做得很好了,然而不同于英文的是,中文句子中没有词的界限,无法简单地通过空格、标点符号进行分词。因此在进行中文自然语言处理时的分词效果将直接影响词性、句法树等模块的效果,一个好的中文分词方法能够使得查询事半功倍。项目中通过开发自定义中文分词器,从而对查询分词进行了一定的优化。
中文分词根据实现原理和特点,主要分为基于词典分词算法和基于统计的机器学习算法。基于词典分词算法是按照一定的策略将待匹配的字符串和一个已建立好的词典中的词进行匹配,若找到某个词条,则说明匹配成功,识别了该词。常见的基于词典的分词算法分为以下几种:正向匹配法、逆向大匹配法和双向匹配分词法等。基于统计的机器学习算法目前常用的算法是HMM、CRF、SVM、深度学习等算法。基本思路是对汉字进行标注训练,不仅考虑了词语出现的频率,还兼顾了上下文,具备较好的学习能力,因此其对歧义词和未登录词的识别都具有良好的效果。
插入一条索引POST test_index/_doc{ "mESsage":"数据解析失败"}对字段应用crf_analyzer分词POST test_index/_analyze{ "analyzer":"crf_analyzer", "text": "数据解析失败"}分词效果如下{ "tokens" : [ { "token" : "数据", "start_offset" : , "end_offset" : 2, "type" : "<IDEOGRAPHIC>", "position" : }, { "token" : "解析", "start_offset" : 3, "end_offset" : 5, "type" : "<IDEOGRAPHIC>", "position" : 1 } { "token" : "失败", "start_offset" : 6, "end_offset" : 8, "type" : "<IDEOGRAPHIC>", "position" : 2 } ]}
自定义中文分词插件应用于查询分词,给涉及中文的日志查询提供了便利,通过过滤大量的信息,提高了查询日志的效率。
3. 总结
原文链接:https://mp.weixin.qq.com/s/724guj6FcDJAkDzu7KNV1A
相关文章