web-dev-qa-db-ja.com

Elasticsearch:マッピングで解析できなかったドキュメントを「レスキュー」する方法は?

ElasticSearchを使用して、インフラストラクチャからのログを保存および検査しています。これらのログの一部は法律で義務付けられており、失うわけにはいきません。

マッピングなしでかなり長い間ログを解析してきました。そのため、検索やグラフ化にはほとんど使用できません。たとえば、一部の整数フィールドは自動的にテキストとして認識されるため、ヒストグラムに集約することはできません。

新しいインデックスの問題を解決するテンプレートとマッピングを導入したいと思います。

ただし、マッピングがあると、解析の失敗への扉も開かれることに気づきました。フィールドが整数として定義されているが、突然整数以外の値を取得した場合、解析は失敗し、ドキュメントは拒否されます。

それらのドキュメントが移動する場所や、後で検査するために保存する方法はありますか?

以下のPythonスクリプトは、ローカルESインスタンスで機能します。

#!/usr/bin/env python3

import requests
import JSON
from typing import Any, Dict


ES_Host = "http://localhost:9200"


def es_request(method: str, path: str, data: Dict[str, Any]) -> None:
    response = requests.request(method, f"{ES_Host}{path}", json=data)

    if response.status_code != 200:
        print(response.content)


es_request('put', '/_template/my_template', {
    "index_patterns": ["my_index"],
    "mappings": {
        "properties": {
            "some_integer": { "type": "integer" }
        }
    }
})

# This is fine
es_request('put', '/my_index/_doc/1', {
    'some_integer': 42
})

# This will be rejected by ES, as it doesn't match the mapping.
# But how can I save it?
es_request('put', '/my_index/_doc/2', {
    'some_integer': 'hello world'
})

スクリプトを実行すると、次のエラーが発生します。

{
    "error": {
        "root_cause": [
            {
                "type": "mapper_parsing_exception",
                "reason":"failed to parse field [some_integer] of type [integer] in document with id '2'. Preview of field's value: 'hello world'"
            }
        ],
        "type": "mapper_parsing_exception",
        "reason":"failed to parse field [some_integer] of type [integer] in document with id '2'. Preview of field's value: 'hello world'",
        "caused_by": {
            "type": "number_format_exception",
            "reason": "For input string: \"hello world\""
        }
    },
    "status": 400
}

そして、ドキュメントが失われるか、そう思われます。ドキュメントを自動的に別の場所に保存するオプション、一種のデッドレターキューを設定できますか?

tl; dr:マッピングが必要ですが、解析エラーのためにログ行を失うわけにはいきません。マッピングに適合しないドキュメントを別の場所に自動的に保存できますか?

2
aspyct

「不正な」属性を許可するのと同じくらい簡単であることがわかります。これを行うには2つの方法があります。インデックス全体のいずれか:

PUT /_template/ignore_malformed_attributes
{
  "index_patterns": ["my_index"],
  "settings": {
      "index.mapping.ignore_malformed": true
  }
}

または属性ごと(ここの例を参照してください: https://www.elastic.co/guide/en/elasticsearch/reference/current/ignore-malformed.html

PUT my_index
{
  "mappings": {
    "properties": {
      "number_one": {
        "type": "integer",
        "ignore_malformed": true
      },
      "number_two": {
        "type": "integer"
      }
    }
  }
}

# Will work
PUT my_index/_doc/1
{
  "text":       "Some text value",
  "number_one": "foo" 
}

# Will be rejected
PUT my_index/_doc/2
{
  "text":       "Some text value",
  "number_two": "foo" 
}

既存のインデックスのプロパティを変更することもできますが、最初にプロパティを閉じる必要があることに注意してください。

POST my_existing_index/_close
PUT my_existing_index/_settings
{
  "index.mapping.ignore_malformed": false
}
POST my_existing_index/_open

[〜#〜] note [〜#〜]:インデックスパターンを更新するまで、タイプの変更はkibanaに表示されません。次に、タイプの競合が発生します。これにより、データのインデックスを再作成して、データを再度検索する必要があります...なんて苦痛でしょう。

POST _reindex
{
  "source": {
    "index": "my_index"
  },
  "dest": {
    "index": "my_new_index"
  }
}

https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-reindex.html

1
aspyct

かなりのユースケースに適している可能性のある代替アプローチは、プロデューサーとElasticseaechの間にログスタッシュを配置することです。 logstashは、特定のインデックスへの再フォーマットやチェック、ルーティングを行うことができます。
またはもちろん、ネイティブプロデューサーがいる場合は、検証してルーティングします。

0
EOhm