Mappingがマージされてしまう件

最近触り始めた者ですが、インデックスとマッピングについて意図したとおりに作成できず、
お力添えいただければと思います。

Linux上ですべてyumで構築した Logstash-Elasticsearch-Kibana の構成において、
・任意のフォーマットのファイルA -> /etc/logstash/conf.d/ファイルA用の定義 -> elasticsearch index => A -> A用のマッピングテンプレート
・任意のフォーマットのファイルB -> /etc/logstash/conf.d/ファイルB用の定義 -> elasticsearch index => B -> A用のマッピングテンプレート
とし、initctlでサービスとしてLogstashを起動した時、
ElasticSearch上にはA、BそれぞれのIndexが生成されるのですが、マッピングが
・Aのマッピング:Logstashのデフォルト?+A用に定義したテンプレートのマッピング
・Bのマッピング:Logstashのデフォルト?+A用に定義したテンプレートのマッピング+B用に定義したテンプレートのマッピング
のように認識されてしまいます。

これを厳密に分離して管理したいのですが、どこでどのような設定を入れるべきなのでしょうか。

なお、マッピングテンプレートで
"dynamic": "strict"
を追加したら、マッピングがマージされるのは防げたのですが、
Indexの器だけが生成されて中身は空(Logstashからデータ登録できていない)となってしまいました。

Logstashが利用しているテンプレートの機能は、実際にはElasticsearchのIndex Templateという機能になります。
このとき、Index Templateのtemplateというパラメータの指定の仕方によって、複数のテンプレートがインデックスのマッピングなどの元に利用されます。
https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-templates.html#multiple-templates

おそらく、templateのパラメータがインデックス名に関連しているものになっているのかと思われます。
A、Bとされているインデックス名は実際にはlogstash-A-?logstash-A-B-?のようなものではないでしょうか?

Indexは、logstashのelasticsearch output pluginでのconf指定に基づいて
xxx-yyy-A-%{+YYYY.MM.dd}
xxx-yyy-B-%{+YYYY.MM.dd}

にて作成されており、templateの指定は、

PUT _template/yyy-A
{
  "template": "xxx-yyy-A-*",
   "yyy-A": {
   "date_detection": false,
   "properties": {
    ・・・
}

PUT _template/yyy-B
{
  "template": "xxx-yyy-B-*",
   "yyy-B": {
   "date_detection": false,
   "properties": {
    ・・・
}

のような指定で作成しています。

いずれも、logstashのデフォルトと重複しないよう、
xxx-の部分はlogstash-の形式を避けて指定し、
index、templateともにそのように作成されています。

KibanaのManagement画面からも
それぞれの形式でIndex Patternsが検出されますが、
作成されたIndex PetternはMappingがマージされたものとなります。

(冒頭でバージョンを書き忘れましたが、5.5です。他のバージョンは試したことがありません。)

何度か試されながらKibanaのIndex Patternの画面を見ているようであれば、一度、Index Patternの画面でリロードをしてみるのがいいかと思います。

https://www.elastic.co/guide/en/kibana/current/index-patterns.html#reload-fields

「Mappingがマージされている」とおっしゃっているのは、Kibanaの画面で確認されている時点でのことでしょうか?
それとも、GET xxx-yyy-B-2017.05.05/_mappingsで取得したもののフィールドがマージされているものになっていますでしょうか?

GET _mappingsで取得した結果がマージされています。

具体的にlogstashの設定を張り付けていただけますでしょうか?あと、ディレクトリにあるファイルの一覧も張り付けていただけますでしょうか?

以下、具体的なLogstashの設定です。

/etc/logstash/conf.d/配下には、(A-1)(A-2)のファイル以外には存在していません。

(A)MySQLに対してSHOW GLOBAL STATUSを実行した結果をログファイルに出力、Logstash経由でelasticsearchへ

mysql -h ホスト名 -u ユーザー名 -pパスワード -e "SHOW GLOBAL STATUS;" | sed -e 's/\t/\" \"/g' | sed -e 's/^/\"/g' | sed -e 's/$/\"/g' | sed -e "s/^/$(date '+%Y\/%m\/%d %H:%M:%S') /g" >> 出力先ファイル

(B)MySQLに対してSHOW FULL PROCESSLISTを実行した結果をログファイルに出力、Logstash経由でelasticsearchへ

mysql -h ホスト名 -u ユーザー名 -pパスワード -e "SHOW FULL PROCESSLIST;" | sed -e 's/\t/\" \"/g' | sed -e 's/^/\"/g' | sed -e 's/$/\"/g' | sed -e "s/^/$(date '+%Y\/%m\/%d %H:%M:%S') /g" >> 出力先ファイル

* 文字数がこちらの入力上限に達したようなので、(B)の分は別レスにて張り付けます。

(A-1)Logstashの設定
/usr/share/logstash/conf.d/mysql_global_status.conf

input {
    file {
        path => "/var/log/mysql_monitor/show_global_status.log"
        start_position => "beginning"
        type => "mysql-status"
    }
}
filter {
    grok {
        match => { "message" => '%{DATESTAMP:date} "%{DATA:Variable_name}" "%{INT:Variable_value}"' }
    }
}
output {
    if [type] == "mysql-status" {
      elasticsearch {
        hosts => [ "localhost:9200" ]
        index => "lgs-mysql-status-%{+YYYY.MM.dd}"
        manage_template => false
        template_name => "lgs-mysql-status"
      }
    }
#     stdout { codec => rubydebug }
}

(A-2)Mapping設定に使用したコマンド

PUT _template/mysql-status
{
  "template": "lgs-mysql-status-*", 
   "mappings": {
     "mysql-status": {
       "date_detection": false,
       "properties": {
         "@timestamp": {
           "type": "date"
         },
         "Variable_name": {
           "type": "text"
         },
         "Variable_value": {
           "type": "long"
         }
       }
      }
   }
}

(A-3)Mappingの確認結果・・・Variable_name、Variable_value以外の項目はLogstashのデフォルト?

GET lgs-mysql-status-2017.07.24/_mappings
{
  "lgs-mysql-status-2017.07.24": {
    "mappings": {
      "mysql-status": {
        "date_detection": false,
        "properties": {
          "@timestamp": {
            "type": "date"
          },
          "@version": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "Variable_name": {
            "type": "text"
          },
          "Variable_value": {
            "type": "long"
          },
          "date": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "host": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "message": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "path": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "tags": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "type": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          }
        }
      }
    }
  }
}

(B-1)Logstashの設定
/usr/share/logstash/conf.d/mysql_show_full_processlist.conf

input {
    file {
        path => "/var/log/mysql_monitor/show_full_processlist.log"
        start_position => "beginning"
        type => "mysql-processlist"
    }
}
filter {
    grok {
        match => { "message" => '%{DATESTAMP:date} "%{DATA:Proc_id}" "%{DATA:Mysql_user_name}" "%{DATA:Client_host}" "%{DATA:Db_schema}" "%{DATA:Command}" "%{INT:Timer}" "%{DATA:State}" "%{DATA:Info}"' }
    }
}
output {
    if [type] == "mysql-processlist" {
      elasticsearch {    
        hosts => [ "localhost:9200" ]
        index => "lgs-mysql-processlist-%{+YYYY.MM.dd}"
        manage_template => false
        template_name => "lgs-mysql-processlist"
      }
    }
#    stdout { codec => rubydebug }
}

(B-2)Mapping設定に使用したコマンド

PUT _template/mysql-processlist
{
  "template": "lgs-mysql-processlist-*", 
  "mappings": {
    "mysql-processlist": {
      "properties": {
        "@timestamp": {
        "type": "date"
      },
        "Proc_id": {
        "type": "text"
      },
        "Mysql_user_name": {
        "type": "text"
      },
        "Client_host": {
        "type": "text"
      },        
        "Db_schema": {
        "type": "text"
      },        
        "Command": {
        "type": "text"
      },
        "Timer": {
        "type": "long"
      },
        "State": {
        "type": "text"
      },
        "Info": {
        "type": "text"
      }
      }
    }
  }
}

(B-3)Mappingの確認結果・・・(A)で定義したVariable_name、Variable_value等が混じっている。
GET lgs-mysql-processlist-2017.07.24/_mappings

{
  "lgs-mysql-processlist-2017.07.24": {
    "mappings": {
      "mysql-processlist": {
        "properties": {
          "@timestamp": {
            "type": "date"
          },
          "@version": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "Client_host": {
            "type": "text"
          },
          "Command": {
            "type": "text"
          },
          "Db_schema": {
            "type": "text"
          },
          "Info": {
            "type": "text"
          },
          "Mysql_user_name": {
            "type": "text"
          },
          "Proc_id": {
            "type": "text"
          },
          "State": {
            "type": "text"
          },
          "Timer": {
            "type": "long"
          },
          "Variable_name": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "Variable_value": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "date": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "host": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "message": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "path": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "tags": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "type": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          }
        }
      }
    }
  }
}

あー、なるほど。
(A-3)にかんしては、Elasticsearchのデフォルトになります。

あと、A-1のtemplate_nameはA-2のmysql-statusにしないときちんと動かないと思いますが。。。

混ざる点に関してはおそらく、grokにもifを書くべきかと。
Logstash内部としては1つの設定(1つのPipeline)になりますので、それぞれのログを読み込んだ後に、2つのgrokが動いているはずです。

参考:

(1)output部におけるtemplate_nameの誤記修正のみ -> 変化なし

(2)filter 部において、grok記述のブロックの外をif[type]=="inputで定義したタイプ"{}で囲む -> 問題解消しました!

.confは1つのファイルで書いても複数のファイルで書いても良いけど、異なるフォーマットのファイルを監視、取込する際にはfilteroutputにはifをつけるべき、ということですね。
outputが別れていて、templateも指定してあっても、その前のfilterを通ってきたデータの構造によって自動判断するmapping定義の方が強い、と。

Logstashは事前にmappingを定義しなくても自動判定でelasticsearchインデックス構造を決めて作ってくれる易しさがある一方、意図したとおりに取り込ませるには、そうした自動判定に入らないように厳密に定義してあげる必要がある、と理解しました。

ありがとうございました。

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.