logstash发送数据到elasticsearch之自定义模板

1 首先配置logstash.conf

# 输入来自filebeat
input {
  beats {
    port => "5044"
  }
}

# 过滤器
filter {

        grok {
                match =>{
                        "message"=>"(?<data>({.*}))"
                }
        }

        grok {
                match =>{
                        "message"=>"%{TIMESTAMP_ISO8601:logTime}"
                }
        }

        grok {
                match =>{
                        "message"=>"%{LOGLEVEL:logLevel}"
                }
        }


        grok {
                match => {
                        "message"=>"(?<userId>(?<=\"userId\":)(\d+))"
                }
        }

        # 设置东八区时间
        ruby {
                code => "event.set('logstashTime', event.get('@timestamp').time.localtime + 8*60*60);
                        event.set('@timestamp', event.get('logstashTime'))"
        }
		
		# 忽略字段
        mutate {
                remove_field => "offset"
                remove_field => "@version"
                remove_field => "input_type"
                # remove_field => "beat"
                remove_field => "host"
                remove_field => "source"
                remove_field => "type"
                remove_field => "tags"
                remove_field => "prospector"
                remove_field => "input"
                remove_field => "log"
        }

}

# 输出追加到日志中
output {
  stdout { codec => rubydebug }
}

# 输出到es
output {
  elasticsearch {
  	# host
    hosts => ["http://elasticsearch:9200"]
    # 开启logstash自动管理模板功能,默认manage_template参数为true, 否则logstash将不会调用Elasticsearch API创建模板。  
    manage_template => true
    # 自定义索引 按照天拆分
    index => "my-log-%{+YYYY.MM.dd}"
    # 自定义类型
    document_type=> "_doc"
    # 映射模板文件所在位置
    template => "/usr/share/logstash/templates/my-log.json"
    #template_name => "my-log"
    # 是否覆盖已存在的模板,template_overwrite为true则template的order高的,满足同样条件(如均以searchlog-开头)的template将覆盖order低的
    template_overwrite => true
  }
}

2 配置模板文件 my-log.json

{
		# 按照名字匹配
        "template": "my-log-*",
        # 排序
        "order": 1,
        # 索引分片等配置
        "settings": {
                "number_of_shards": 1,
                "number_of_replicas": 0,
                "refresh_interval": "60s",
                "index.max_result_window":10000000,
				"index.blocks.read_only_allow_delete":null
        },
        # 映射
        "mappings": {
                "_doc": {
                		# 严格映射
                        "dynamic":"strict",
                        "properties": {

                                "message": {
                                		# 分词器
                                        "analyzer": "ik_max_word",
                                        "index": true,
                                        "store": false,
                                        "type": "text"
                                },

                                "data": {
                                        "analyzer": "ik_max_word",
                                        "index": true,
                                        "store": false,
                                        "type": "text"
                                },

                                "userId": {
                                        "type": "long"
                                },

                                "logLevel": {
                                        "store": false,
                                        "type": "keyword"
                                },
                                "from": {
                                        "store": false,
                                        "type": "keyword"
                                },

                                ""      
                                "@timestamp": {
                                        "format": "strict_date_optional_time||yyyy-MM-dd HH:mm:ss.SSS||epoch_millis",
                                        "type": "date"
                                },

                                "logstashTime": {
                                        "format": "strict_date_optional_time||yyyy-MM-dd HH:mm:ss.SSS||epoch_millis",
                                        "type": "date"
                                },

                                "logTime": {
                                        "format": "strict_date_optional_time||yyyy-MM-dd HH:mm:ss.SSS||epoch_millis",
                                        "type": "date"
                                },

                                        "type": "date"
                                },

                                "beat": {
                                        "properties": {
                                                "hostname": {
                                                        "store": false,
                                                        "type": "keyword"
                                                },
                                                "name": {
                                                        "store": false,
                                                        "type": "keyword"
                                                },
                                                "version": {
                                                        "store": false,
                                                        "type": "keyword"
                                                }
                                        }
                                }

                        }
                }
        }
}

3 关于日期的format

"format": "strict_date_optional_time||yyyy-MM-dd HH:mm:ss.SSS||epoch_millis",
分别对应日期格式 =>
2021-09-09T17:19:21.262Z||2021-09-09 17:19:20.000||时间戳

4 关于"dynamic"字段

一般的,mapping则又可以分为动态映射(dynamic mapping)和静态(显式)映射(explicit mapping)和精确(严格)映射(strict mappings),具体由dynamic属性控制。

  • 动态映射(dynamic:true)
  • 静态映射(dynamic:false)
  • 严格模式(dynamic:strict)

前言

一般的,mapping则又可以分为动态映射(dynamic mapping)和静态(显式)映射(explicit mapping)和精确(严格)映射(strict mappings),具体由dynamic属性控制。

动态映射(dynamic:true)

现在有这样的一个索引:

PUT m1
{
  "mappings": {
    "doc":{
      "properties": {
        "name": {
          "type": "text"
        },
        "age": {
          "type": "long"
        }
      }
    }
  }
}

通过GET m1/_mapping看一下mappings信息:

{
  "m1" : {
    "mappings" : {
      "doc" : {
        "dynamic" : "true",
        "properties" : {
          "age" : {
            "type" : "long"
          },
          "name" : {
            "type" : "text"
          }
        }
      }
    }
  }
}

添加一些数据,并且新增一个sex字段:

PUT m1/doc/1
{
  "name": "小黑",
  "age": 18,
  "sex": "不详"
}

当然,新的字段查询也没问题:

GET m1/doc/_search
{
  "query": {
    "match": {
      "sex": "不详"
    }
  }
}

返回结果:

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 1,
    "max_score" : 0.5753642,
    "hits" : [
      {
        "_index" : "m1",
        "_type" : "doc",
        "_id" : "1",
        "_score" : 0.5753642,
        "_source" : {
          "name" : "小黑",
          "age" : 18,
          "sex" : "不详"
        }
      }
    ]
  }
}

现在,一切都很正常,跟elasticsearch自动创建时一样。那是因为,当 Elasticsearch 遇到文档中以前未遇到的字段,它用动态映射来确定字段的数据类型并自动把新的字段添加到类型映射。我们再来看mappings你就明白了:

{
  "m1" : {
    "mappings" : {
      "doc" : {
        "dynamic" : "true",
        "properties" : {
          "age" : {
            "type" : "long"
          },
          "name" : {
            "type" : "text"
          },
          "sex" : {
            "type" : "text",
            "fields" : {
              "keyword" : {
                "type" : "keyword",
                "ignore_above" : 256
              }
            }
          }
        }
      }
    }
  }
}

通过上例可以发下,elasticsearch帮我们新增了一个sex的映射。所以。这一切看起来如此自然。这一切的功劳都要归功于dynamic属性。我们知道在关系型数据库中,字段创建后除非手动修改,则永远不会更改。但是,elasticsearch默认是允许添加新的字段的,也就是dynamic:true
其实创建索引的时候,是这样的:

PUT m1
{
  "mappings": {
    "doc":{
      "dynamic":true,
      "properties": {
        "name": {
          "type": "text"
        },
        "age": {
          "type": "long"
        }
      }
    }
  }
}

上例中,当dynamic设置为true的时候,elasticsearch就会帮我们动态的添加映射属性。也就是等于啥都没做!
这里有一点需要注意的是:mappings一旦创建,则无法修改。因为Lucene生成倒排索引后就不能改了。

静态映射(dynamic:false)

现在,我们将dynamic值设置为false

PUT m2
{
  "mappings": {
    "doc":{
      "dynamic":false,
      "properties": {
        "name": {
          "type": "text"
        },
        "age": {
          "type": "long"
        }
      }
    }
  }
}

现在再来测试一下falsetrue有什么区别:

PUT m2/doc/1
{
  "name": "小黑",
  "age":18
}
PUT m2/doc/2
{
  "name": "小白",
  "age": 16,
  "sex": "不详"
}

第二条数据相对于第一条数据来说,多了一个sex属性,我们以sex为条件来查询一下:

GET m2/doc/_search
{
  "query": {
    "match": {
      "sex": "不详"
    }
  }
}

结果如下:

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 0,
    "max_score" : null,
    "hits" : [ ]
  }
}

结果是空的,也就是什么都没查询到,那是为什呢?来GET m2/_mapping一下此时m2mappings信息:

{
  "m2" : {
    "mappings" : {
      "doc" : {
        "dynamic" : "false",
        "properties" : {
          "age" : {
            "type" : "long"
          },
          "name" : {
            "type" : "text"
          }
        }
      }
    }
  }
}

可以看到elasticsearch并没有为新增的sex建立映射关系。所以查询不到。
当elasticsearch察觉到有新增字段时,因为dynamic:false的关系,会忽略该字段,但是仍会存储该字段。
在有些情况下,dynamic:false依然不够,所以还需要更严谨的策略来进一步做限制。

严格模式(dynamic:strict)

让我们再创建一个mappings,并且将dynamic的状态改为strict

PUT m3
{
  "mappings": {
    "doc": {
      "dynamic": "strict", 
      "properties": {
        "name": {
          "type": "text"
        },
        "age": {
          "type": "long"
        }
      }
    }
  }
}

现在,添加两篇文档:

PUT m3/doc/1
{
  "name": "小黑",
  "age": 18
}
PUT m3/doc/2
{
  "name": "小白",
  "age": 18,
  "sex": "不详"
}

第一篇文档添加和查询都没问题。但是,当添加第二篇文档的时候,你会发现报错了:

{
  "error": {
    "root_cause": [
      {
        "type": "strict_dynamic_mapping_exception",
        "reason": "mapping set to strict, dynamic introduction of [sex] within [doc] is not allowed"
      }
    ],
    "type": "strict_dynamic_mapping_exception",
    "reason": "mapping set to strict, dynamic introduction of [sex] within [doc] is not allowed"
  },
  "status": 400
}

错误提示,严格动态映射异常!说人话就是,当dynamic:strict的时候,elasticsearch如果遇到新字段,会抛出异常。
上述这种严谨的作风洒家称为——严格模式!

小结:

  • 动态映射(dynamic:true):动态添加新的字段(或缺省)。
  • 静态映射(dynamic:false):忽略新的字段。在原有的映射基础上,当有新的字段时,不会主动的添加新的映射关系,只作为查询结果出现在查询中。
  • 严格模式(dynamic: strict):如果遇到新的字段,就抛出异常。

一般静态映射用的较多。就像HTMLimg标签一样,src为自带的属性,你可以在需要的时候添加id或者class属性。
当然,如果你非常非常了解你的数据,并且未来很长一段时间不会改变,strict不失为一个好选择。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

L-960

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值