ランタイムフィールドでデータを探索する

抽出したいフィールドがある大規模なログデータセットを考えてみてください。データのインデックス作成は時間がかかり、多くのディスクスペースを使用しますが、事前にスキーマを決定せずにデータ構造を探索したいだけです。

ログデータには抽出したい特定のフィールドが含まれていることがわかっています。この場合、@timestampmessageフィールドに焦点を当てます。ランタイムフィールドを使用することで、検索時にこれらのフィールドの値を計算するスクリプトを定義できます。

インデックスフィールドを出発点として定義する

  1. #### Python
  2. ``````python
  3. resp = client.indices.create(
  4. index="my-index-000001",
  5. mappings={
  6. "properties": {
  7. "@timestamp": {
  8. "format": "strict_date_optional_time||epoch_second",
  9. "type": "date"
  10. },
  11. "message": {
  12. "type": "wildcard"
  13. }
  14. }
  15. },
  16. )
  17. print(resp)
  18. `

Ruby

  1. response = client.indices.create(
  2. index: 'my-index-000001',
  3. body: {
  4. mappings: {
  5. properties: {
  6. "@timestamp": {
  7. format: 'strict_date_optional_time||epoch_second',
  8. type: 'date'
  9. },
  10. message: {
  11. type: 'wildcard'
  12. }
  13. }
  14. }
  15. }
  16. )
  17. puts response

Js

  1. const response = await client.indices.create({
  2. index: "my-index-000001",
  3. mappings: {
  4. properties: {
  5. "@timestamp": {
  6. format: "strict_date_optional_time||epoch_second",
  7. type: "date",
  8. },
  9. message: {
  10. type: "wildcard",
  11. },
  12. },
  13. },
  14. });
  15. console.log(response);

Console

  1. PUT /my-index-000001/
  2. {
  3. "mappings": {
  4. "properties": {
  5. "@timestamp": {
  6. "format": "strict_date_optional_time||epoch_second",
  7. "type": "date"
  8. },
  9. "message": {
  10. "type": "wildcard"
  11. }
  12. }
  13. }
  14. }

データを取り込む

取得したいフィールドをマッピングした後、ログデータからいくつかのレコードをElasticsearchにインデックスします。次のリクエストは、bulk APIを使用して、生のログデータをmy-index-000001にインデックスします。すべてのログデータをインデックスする代わりに、小さなサンプルを使用してランタイムフィールドを試すことができます。

最終的なドキュメントは有効なApacheログ形式ではありませんが、そのシナリオをスクリプトで考慮することができます。

Python

  1. resp = client.bulk(
  2. index="my-index-000001",
  3. refresh=True,
  4. operations=[
  5. {
  6. "index": {}
  7. },
  8. {
  9. "timestamp": "2020-04-30T14:30:17-05:00",
  10. "message": "40.135.0.0 - - [30/Apr/2020:14:30:17 -0500] \"GET /images/hm_bg.jpg HTTP/1.0\" 200 24736"
  11. },
  12. {
  13. "index": {}
  14. },
  15. {
  16. "timestamp": "2020-04-30T14:30:53-05:00",
  17. "message": "232.0.0.0 - - [30/Apr/2020:14:30:53 -0500] \"GET /images/hm_bg.jpg HTTP/1.0\" 200 24736"
  18. },
  19. {
  20. "index": {}
  21. },
  22. {
  23. "timestamp": "2020-04-30T14:31:12-05:00",
  24. "message": "26.1.0.0 - - [30/Apr/2020:14:31:12 -0500] \"GET /images/hm_bg.jpg HTTP/1.0\" 200 24736"
  25. },
  26. {
  27. "index": {}
  28. },
  29. {
  30. "timestamp": "2020-04-30T14:31:19-05:00",
  31. "message": "247.37.0.0 - - [30/Apr/2020:14:31:19 -0500] \"GET /french/splash_inet.html HTTP/1.0\" 200 3781"
  32. },
  33. {
  34. "index": {}
  35. },
  36. {
  37. "timestamp": "2020-04-30T14:31:22-05:00",
  38. "message": "247.37.0.0 - - [30/Apr/2020:14:31:22 -0500] \"GET /images/hm_nbg.jpg HTTP/1.0\" 304 0"
  39. },
  40. {
  41. "index": {}
  42. },
  43. {
  44. "timestamp": "2020-04-30T14:31:27-05:00",
  45. "message": "252.0.0.0 - - [30/Apr/2020:14:31:27 -0500] \"GET /images/hm_bg.jpg HTTP/1.0\" 200 24736"
  46. },
  47. {
  48. "index": {}
  49. },
  50. {
  51. "timestamp": "2020-04-30T14:31:28-05:00",
  52. "message": "not a valid apache log"
  53. }
  54. ],
  55. )
  56. print(resp)

Ruby

  1. response = client.bulk(
  2. index: 'my-index-000001',
  3. refresh: true,
  4. body: [
  5. {
  6. index: {}
  7. },
  8. {
  9. timestamp: '2020-04-30T14:30:17-05:00',
  10. message: '40.135.0.0 - - [30/Apr/2020:14:30:17 -0500] "GET /images/hm_bg.jpg HTTP/1.0" 200 24736'
  11. },
  12. {
  13. index: {}
  14. },
  15. {
  16. timestamp: '2020-04-30T14:30:53-05:00',
  17. message: '232.0.0.0 - - [30/Apr/2020:14:30:53 -0500] "GET /images/hm_bg.jpg HTTP/1.0" 200 24736'
  18. },
  19. {
  20. index: {}
  21. },
  22. {
  23. timestamp: '2020-04-30T14:31:12-05:00',
  24. message: '26.1.0.0 - - [30/Apr/2020:14:31:12 -0500] "GET /images/hm_bg.jpg HTTP/1.0" 200 24736'
  25. },
  26. {
  27. index: {}
  28. },
  29. {
  30. timestamp: '2020-04-30T14:31:19-05:00',
  31. message: '247.37.0.0 - - [30/Apr/2020:14:31:19 -0500] "GET /french/splash_inet.html HTTP/1.0" 200 3781'
  32. },
  33. {
  34. index: {}
  35. },
  36. {
  37. timestamp: '2020-04-30T14:31:22-05:00',
  38. message: '247.37.0.0 - - [30/Apr/2020:14:31:22 -0500] "GET /images/hm_nbg.jpg HTTP/1.0" 304 0'
  39. },
  40. {
  41. index: {}
  42. },
  43. {
  44. timestamp: '2020-04-30T14:31:27-05:00',
  45. message: '252.0.0.0 - - [30/Apr/2020:14:31:27 -0500] "GET /images/hm_bg.jpg HTTP/1.0" 200 24736'
  46. },
  47. {
  48. index: {}
  49. },
  50. {
  51. timestamp: '2020-04-30T14:31:28-05:00',
  52. message: 'not a valid apache log'
  53. }
  54. ]
  55. )
  56. puts response

Js

  1. const response = await client.bulk({
  2. index: "my-index-000001",
  3. refresh: "true",
  4. operations: [
  5. {
  6. index: {},
  7. },
  8. {
  9. timestamp: "2020-04-30T14:30:17-05:00",
  10. message:
  11. '40.135.0.0 - - [30/Apr/2020:14:30:17 -0500] "GET /images/hm_bg.jpg HTTP/1.0" 200 24736',
  12. },
  13. {
  14. index: {},
  15. },
  16. {
  17. timestamp: "2020-04-30T14:30:53-05:00",
  18. message:
  19. '232.0.0.0 - - [30/Apr/2020:14:30:53 -0500] "GET /images/hm_bg.jpg HTTP/1.0" 200 24736',
  20. },
  21. {
  22. index: {},
  23. },
  24. {
  25. timestamp: "2020-04-30T14:31:12-05:00",
  26. message:
  27. '26.1.0.0 - - [30/Apr/2020:14:31:12 -0500] "GET /images/hm_bg.jpg HTTP/1.0" 200 24736',
  28. },
  29. {
  30. index: {},
  31. },
  32. {
  33. timestamp: "2020-04-30T14:31:19-05:00",
  34. message:
  35. '247.37.0.0 - - [30/Apr/2020:14:31:19 -0500] "GET /french/splash_inet.html HTTP/1.0" 200 3781',
  36. },
  37. {
  38. index: {},
  39. },
  40. {
  41. timestamp: "2020-04-30T14:31:22-05:00",
  42. message:
  43. '247.37.0.0 - - [30/Apr/2020:14:31:22 -0500] "GET /images/hm_nbg.jpg HTTP/1.0" 304 0',
  44. },
  45. {
  46. index: {},
  47. },
  48. {
  49. timestamp: "2020-04-30T14:31:27-05:00",
  50. message:
  51. '252.0.0.0 - - [30/Apr/2020:14:31:27 -0500] "GET /images/hm_bg.jpg HTTP/1.0" 200 24736',
  52. },
  53. {
  54. index: {},
  55. },
  56. {
  57. timestamp: "2020-04-30T14:31:28-05:00",
  58. message: "not a valid apache log",
  59. },
  60. ],
  61. });
  62. console.log(response);

Console

  1. POST /my-index-000001/_bulk?refresh
  2. {"index":{}}
  3. {"timestamp":"2020-04-30T14:30:17-05:00","message":"40.135.0.0 - - [30/Apr/2020:14:30:17 -0500] \"GET /images/hm_bg.jpg HTTP/1.0\" 200 24736"}
  4. {"index":{}}
  5. {"timestamp":"2020-04-30T14:30:53-05:00","message":"232.0.0.0 - - [30/Apr/2020:14:30:53 -0500] \"GET /images/hm_bg.jpg HTTP/1.0\" 200 24736"}
  6. {"index":{}}
  7. {"timestamp":"2020-04-30T14:31:12-05:00","message":"26.1.0.0 - - [30/Apr/2020:14:31:12 -0500] \"GET /images/hm_bg.jpg HTTP/1.0\" 200 24736"}
  8. {"index":{}}
  9. {"timestamp":"2020-04-30T14:31:19-05:00","message":"247.37.0.0 - - [30/Apr/2020:14:31:19 -0500] \"GET /french/splash_inet.html HTTP/1.0\" 200 3781"}
  10. {"index":{}}
  11. {"timestamp":"2020-04-30T14:31:22-05:00","message":"247.37.0.0 - - [30/Apr/2020:14:31:22 -0500] \"GET /images/hm_nbg.jpg HTTP/1.0\" 304 0"}
  12. {"index":{}}
  13. {"timestamp":"2020-04-30T14:31:27-05:00","message":"252.0.0.0 - - [30/Apr/2020:14:31:27 -0500] \"GET /images/hm_bg.jpg HTTP/1.0\" 200 24736"}
  14. {"index":{}}
  15. {"timestamp":"2020-04-30T14:31:28-05:00","message":"not a valid apache log"}

この時点で、Elasticsearchが生データをどのように保存しているかを確認できます。

Python

  1. resp = client.indices.get(
  2. index="my-index-000001",
  3. )
  4. print(resp)

Ruby

  1. response = client.indices.get(
  2. index: 'my-index-000001'
  3. )
  4. puts response

Js

  1. const response = await client.indices.get({
  2. index: "my-index-000001",
  3. });
  4. console.log(response);

Console

  1. GET /my-index-000001

マッピングには、@timestampmessageの2つのフィールドが含まれています。

Console-Result

  1. {
  2. "my-index-000001" : {
  3. "aliases" : { },
  4. "mappings" : {
  5. "properties" : {
  6. "@timestamp" : {
  7. "type" : "date",
  8. "format" : "strict_date_optional_time||epoch_second"
  9. },
  10. "message" : {
  11. "type" : "wildcard"
  12. },
  13. "timestamp" : {
  14. "type" : "date"
  15. }
  16. }
  17. },
  18. ...
  19. }
  20. }

grokパターンでランタイムフィールドを定義する

  1. スクリプトは、Apacheログの構造を理解する`````%{COMMONAPACHELOG}`````ログパターンにマッチします。パターンが一致すると(`````clientip != null`````)、スクリプトは一致したIPアドレスの値を出力します。パターンが一致しない場合、スクリプトはクラッシュせずにフィールド値を返します。
  2. #### Python
  3. ``````python
  4. resp = client.indices.put_mapping(
  5. index="my-index-000001",
  6. runtime={
  7. "http.client_ip": {
  8. "type": "ip",
  9. "script": "\n String clientip=grok('%{COMMONAPACHELOG}').extract(doc[\"message\"].value)?.clientip;\n if (clientip != null) emit(clientip); \n "
  10. }
  11. },
  12. )
  13. print(resp)
  14. `

Js

  1. const response = await client.indices.putMapping({
  2. index: "my-index-000001",
  3. runtime: {
  4. "http.client_ip": {
  5. type: "ip",
  6. script:
  7. "\n String clientip=grok('%{COMMONAPACHELOG}').extract(doc[\"message\"].value)?.clientip;\n if (clientip != null) emit(clientip); \n ",
  8. },
  9. },
  10. });
  11. console.log(response);

Console

  1. PUT my-index-000001/_mappings
  2. {
  3. "runtime": {
  4. "http.client_ip": {
  5. "type": "ip",
  6. "script": """
  7. String clientip=grok('%{COMMONAPACHELOG}').extract(doc["message"].value)?.clientip;
  8. if (clientip != null) emit(clientip);
  9. """
  10. }
  11. }
  12. }
この条件は、メッセージのパターンが一致しなくてもスクリプトがクラッシュしないことを保証します。

また、同じランタイムフィールドを検索リクエストのコンテキストで定義することもできます。ランタイム定義とスクリプトは、インデックスマッピングで以前に定義したものとまったく同じです。その定義をruntime_mappingsセクションの検索リクエストにコピーし、ランタイムフィールドに一致するクエリを含めます。このクエリは、インデックスマッピングでhttp.clientipランタイムフィールドの検索クエリを定義した場合と同じ結果を返しますが、この特定の検索のコンテキスト内でのみです:

Python

  1. resp = client.search(
  2. index="my-index-000001",
  3. runtime_mappings={
  4. "http.clientip": {
  5. "type": "ip",
  6. "script": "\n String clientip=grok('%{COMMONAPACHELOG}').extract(doc[\"message\"].value)?.clientip;\n if (clientip != null) emit(clientip);\n "
  7. }
  8. },
  9. query={
  10. "match": {
  11. "http.clientip": "40.135.0.0"
  12. }
  13. },
  14. fields=[
  15. "http.clientip"
  16. ],
  17. )
  18. print(resp)

Js

  1. const response = await client.search({
  2. index: "my-index-000001",
  3. runtime_mappings: {
  4. "http.clientip": {
  5. type: "ip",
  6. script:
  7. "\n String clientip=grok('%{COMMONAPACHELOG}').extract(doc[\"message\"].value)?.clientip;\n if (clientip != null) emit(clientip);\n ",
  8. },
  9. },
  10. query: {
  11. match: {
  12. "http.clientip": "40.135.0.0",
  13. },
  14. },
  15. fields: ["http.clientip"],
  16. });
  17. console.log(response);

Console

  1. GET my-index-000001/_search
  2. {
  3. "runtime_mappings": {
  4. "http.clientip": {
  5. "type": "ip",
  6. "script": """
  7. String clientip=grok('%{COMMONAPACHELOG}').extract(doc["message"].value)?.clientip;
  8. if (clientip != null) emit(clientip);
  9. """
  10. }
  11. },
  12. "query": {
  13. "match": {
  14. "http.clientip": "40.135.0.0"
  15. }
  16. },
  17. "fields" : ["http.clientip"]
  18. }

複合ランタイムフィールドを定義する

単一のスクリプトから複数のフィールドを出力する複合ランタイムフィールドを定義することもできます。型付きのサブフィールドのセットを定義し、値のマップを出力できます。検索時に、各サブフィールドはマップ内の名前に関連付けられた値を取得します。これにより、grokパターンを1回だけ指定し、複数の値を返すことができます:

Python

  1. resp = client.indices.put_mapping(
  2. index="my-index-000001",
  3. runtime={
  4. "http": {
  5. "type": "composite",
  6. "script": "emit(grok(\"%{COMMONAPACHELOG}\").extract(doc[\"message\"].value))",
  7. "fields": {
  8. "clientip": {
  9. "type": "ip"
  10. },
  11. "verb": {
  12. "type": "keyword"
  13. },
  14. "response": {
  15. "type": "long"
  16. }
  17. }
  18. }
  19. },
  20. )
  21. print(resp)

Ruby

  1. response = client.indices.put_mapping(
  2. index: 'my-index-000001',
  3. body: {
  4. runtime: {
  5. http: {
  6. type: 'composite',
  7. script: 'emit(grok("%<COMMONAPACHELOG>s").extract(doc["message"].value))',
  8. fields: {
  9. clientip: {
  10. type: 'ip'
  11. },
  12. verb: {
  13. type: 'keyword'
  14. },
  15. response: {
  16. type: 'long'
  17. }
  18. }
  19. }
  20. }
  21. }
  22. )
  23. puts response

Js

  1. const response = await client.indices.putMapping({
  2. index: "my-index-000001",
  3. runtime: {
  4. http: {
  5. type: "composite",
  6. script: 'emit(grok("%{COMMONAPACHELOG}").extract(doc["message"].value))',
  7. fields: {
  8. clientip: {
  9. type: "ip",
  10. },
  11. verb: {
  12. type: "keyword",
  13. },
  14. response: {
  15. type: "long",
  16. },
  17. },
  18. },
  19. },
  20. });
  21. console.log(response);

Console

  1. PUT my-index-000001/_mappings
  2. {
  3. "runtime": {
  4. "http": {
  5. "type": "composite",
  6. "script": "emit(grok(\"%{COMMONAPACHELOG}\").extract(doc[\"message\"].value))",
  7. "fields": {
  8. "clientip": {
  9. "type": "ip"
  10. },
  11. "verb": {
  12. "type": "keyword"
  13. },
  14. "response": {
  15. "type": "long"
  16. }
  17. }
  18. }
  19. }
  20. }

特定のIPアドレスを検索する

  1. #### Python
  2. ``````python
  3. resp = client.search(
  4. index="my-index-000001",
  5. query={
  6. "match": {
  7. "http.clientip": "40.135.0.0"
  8. }
  9. },
  10. fields=[
  11. "*"
  12. ],
  13. )
  14. print(resp)
  15. `

Js

  1. const response = await client.search({
  2. index: "my-index-000001",
  3. query: {
  4. match: {
  5. "http.clientip": "40.135.0.0",
  6. },
  7. },
  8. fields: ["*"],
  9. });
  10. console.log(response);

Console

  1. GET my-index-000001/_search
  2. {
  3. "query": {
  4. "match": {
  5. "http.clientip": "40.135.0.0"
  6. }
  7. },
  8. "fields" : ["*"]
  9. }

APIは次の結果を返します。httpcompositeランタイムフィールドであるため、レスポンスにはfieldsの下にある各サブフィールドが含まれ、クエリに一致する関連する値が含まれます。事前にデータ構造を構築することなく、データを意味のある方法で検索および探索し、インデックスするフィールドを決定することができます。

Console-Result

  1. {
  2. ...
  3. "hits" : {
  4. "total" : {
  5. "value" : 1,
  6. "relation" : "eq"
  7. },
  8. "max_score" : 1.0,
  9. "hits" : [
  10. {
  11. "_index" : "my-index-000001",
  12. "_id" : "sRVHBnwBB-qjgFni7h_O",
  13. "_score" : 1.0,
  14. "_source" : {
  15. "timestamp" : "2020-04-30T14:30:17-05:00",
  16. "message" : "40.135.0.0 - - [30/Apr/2020:14:30:17 -0500] \"GET /images/hm_bg.jpg HTTP/1.0\" 200 24736"
  17. },
  18. "fields" : {
  19. "http.verb" : [
  20. "GET"
  21. ],
  22. "http.clientip" : [
  23. "40.135.0.0"
  24. ],
  25. "http.response" : [
  26. 200
  27. ],
  28. "message" : [
  29. "40.135.0.0 - - [30/Apr/2020:14:30:17 -0500] \"GET /images/hm_bg.jpg HTTP/1.0\" 200 24736"
  30. ],
  31. "http.client_ip" : [
  32. "40.135.0.0"
  33. ],
  34. "timestamp" : [
  35. "2020-04-30T19:30:17.000Z"
  36. ]
  37. }
  38. }
  39. ]
  40. }
  41. }

また、スクリプト内のifステートメントを覚えていますか?

Painless

  1. if (clientip != null) emit(clientip);

スクリプトにこの条件が含まれていなかった場合、クエリはパターンに一致しないシャードで失敗します。この条件を含めることで、クエリはgrokパターンに一致しないデータをスキップします。

特定の範囲内のドキュメントを検索する

  1. #### Python
  2. ``````python
  3. resp = client.search(
  4. index="my-index-000001",
  5. query={
  6. "range": {
  7. "timestamp": {
  8. "gte": "2020-04-30T14:31:27-05:00"
  9. }
  10. }
  11. },
  12. )
  13. print(resp)
  14. `

Js

  1. const response = await client.search({
  2. index: "my-index-000001",
  3. query: {
  4. range: {
  5. timestamp: {
  6. gte: "2020-04-30T14:31:27-05:00",
  7. },
  8. },
  9. },
  10. });
  11. console.log(response);

Console

  1. GET my-index-000001/_search
  2. {
  3. "query": {
  4. "range": {
  5. "timestamp": {
  6. "gte": "2020-04-30T14:31:27-05:00"
  7. }
  8. }
  9. }
  10. }

レスポンスには、ログ形式が一致しないドキュメントが含まれていますが、タイムスタンプは定義された範囲内にあります。

Console-Result

  1. {
  2. ...
  3. "hits" : {
  4. "total" : {
  5. "value" : 2,
  6. "relation" : "eq"
  7. },
  8. "max_score" : 1.0,
  9. "hits" : [
  10. {
  11. "_index" : "my-index-000001",
  12. "_id" : "hdEhyncBRSB6iD-PoBqe",
  13. "_score" : 1.0,
  14. "_source" : {
  15. "timestamp" : "2020-04-30T14:31:27-05:00",
  16. "message" : "252.0.0.0 - - [30/Apr/2020:14:31:27 -0500] \"GET /images/hm_bg.jpg HTTP/1.0\" 200 24736"
  17. }
  18. },
  19. {
  20. "_index" : "my-index-000001",
  21. "_id" : "htEhyncBRSB6iD-PoBqe",
  22. "_score" : 1.0,
  23. "_source" : {
  24. "timestamp" : "2020-04-30T14:31:28-05:00",
  25. "message" : "not a valid apache log"
  26. }
  27. }
  28. ]
  29. }
  30. }

dissectパターンでランタイムフィールドを定義する

正規表現の力が必要ない場合は、grokパターンの代わりにdissectパターンを使用できます。dissectパターンは固定の区切り文字にマッチしますが、通常はgrokよりも高速です。

dissectを使用して、Apacheログをgrokパターンで解析するのと同じ結果を得ることができます。ログパターンにマッチするのではなく、破棄したい文字列の部分を含めます。破棄したい文字列の部分に特に注意を払うことで、成功するdissectパターンを構築するのに役立ちます。

Python

  1. resp = client.indices.put_mapping(
  2. index="my-index-000001",
  3. runtime={
  4. "http.client.ip": {
  5. "type": "ip",
  6. "script": "\n String clientip=dissect('%{clientip} %{ident} %{auth} [%{@timestamp}] \"%{verb} %{request} HTTP/%{httpversion}\" %{status} %{size}').extract(doc[\"message\"].value)?.clientip;\n if (clientip != null) emit(clientip);\n "
  7. }
  8. },
  9. )
  10. print(resp)

Js

  1. const response = await client.indices.putMapping({
  2. index: "my-index-000001",
  3. runtime: {
  4. "http.client.ip": {
  5. type: "ip",
  6. script:
  7. '\n String clientip=dissect(\'%{clientip} %{ident} %{auth} [%{@timestamp}] "%{verb} %{request} HTTP/%{httpversion}" %{status} %{size}\').extract(doc["message"].value)?.clientip;\n if (clientip != null) emit(clientip);\n ',
  8. },
  9. },
  10. });
  11. console.log(response);

Console

  1. PUT my-index-000001/_mappings
  2. {
  3. "runtime": {
  4. "http.client.ip": {
  5. "type": "ip",
  6. "script": """
  7. String clientip=dissect('%{clientip} %{ident} %{auth} [%{@timestamp}] "%{verb} %{request} HTTP/%{httpversion}" %{status} %{size}').extract(doc["message"].value)?.clientip;
  8. if (clientip != null) emit(clientip);
  9. """
  10. }
  11. }
  12. }

同様に、HTTPレスポンスコードを抽出するためのdissectパターンを定義できます:

Python

  1. resp = client.indices.put_mapping(
  2. index="my-index-000001",
  3. runtime={
  4. "http.responses": {
  5. "type": "long",
  6. "script": "\n String response=dissect('%{clientip} %{ident} %{auth} [%{@timestamp}] \"%{verb} %{request} HTTP/%{httpversion}\" %{response} %{size}').extract(doc[\"message\"].value)?.response;\n if (response != null) emit(Integer.parseInt(response));\n "
  7. }
  8. },
  9. )
  10. print(resp)

Js

  1. const response = await client.indices.putMapping({
  2. index: "my-index-000001",
  3. runtime: {
  4. "http.responses": {
  5. type: "long",
  6. script:
  7. '\n String response=dissect(\'%{clientip} %{ident} %{auth} [%{@timestamp}] "%{verb} %{request} HTTP/%{httpversion}" %{response} %{size}\').extract(doc["message"].value)?.response;\n if (response != null) emit(Integer.parseInt(response));\n ',
  8. },
  9. },
  10. });
  11. console.log(response);

Console

  1. PUT my-index-000001/_mappings
  2. {
  3. "runtime": {
  4. "http.responses": {
  5. "type": "long",
  6. "script": """
  7. String response=dissect('%{clientip} %{ident} %{auth} [%{@timestamp}] "%{verb} %{request} HTTP/%{httpversion}" %{response} %{size}').extract(doc["message"].value)?.response;
  8. if (response != null) emit(Integer.parseInt(response));
  9. """
  10. }
  11. }
  12. }

次に、http.responsesランタイムフィールドを使用して特定のHTTPレスポンスを取得するクエリを実行できます。_searchリクエストのfieldsパラメータを使用して、取得したいフィールドを指定します:

Python

  1. resp = client.search(
  2. index="my-index-000001",
  3. query={
  4. "match": {
  5. "http.responses": "304"
  6. }
  7. },
  8. fields=[
  9. "http.client_ip",
  10. "timestamp",
  11. "http.verb"
  12. ],
  13. )
  14. print(resp)

Ruby

  1. response = client.search(
  2. index: 'my-index-000001',
  3. body: {
  4. query: {
  5. match: {
  6. 'http.responses' => '304'
  7. }
  8. },
  9. fields: [
  10. 'http.client_ip',
  11. 'timestamp',
  12. 'http.verb'
  13. ]
  14. }
  15. )
  16. puts response

Js

  1. const response = await client.search({
  2. index: "my-index-000001",
  3. query: {
  4. match: {
  5. "http.responses": "304",
  6. },
  7. },
  8. fields: ["http.client_ip", "timestamp", "http.verb"],
  9. });
  10. console.log(response);

Console

  1. GET my-index-000001/_search
  2. {
  3. "query": {
  4. "match": {
  5. "http.responses": "304"
  6. }
  7. },
  8. "fields" : ["http.client_ip","timestamp","http.verb"]
  9. }

レスポンスには、HTTPレスポンスが304である単一のドキュメントが含まれています。

Console-Result

  1. {
  2. ...
  3. "hits" : {
  4. "total" : {
  5. "value" : 1,
  6. "relation" : "eq"
  7. },
  8. "max_score" : 1.0,
  9. "hits" : [
  10. {
  11. "_index" : "my-index-000001",
  12. "_id" : "A2qDy3cBWRMvVAuI7F8M",
  13. "_score" : 1.0,
  14. "_source" : {
  15. "timestamp" : "2020-04-30T14:31:22-05:00",
  16. "message" : "247.37.0.0 - - [30/Apr/2020:14:31:22 -0500] \"GET /images/hm_nbg.jpg HTTP/1.0\" 304 0"
  17. },
  18. "fields" : {
  19. "http.verb" : [
  20. "GET"
  21. ],
  22. "http.client_ip" : [
  23. "247.37.0.0"
  24. ],
  25. "timestamp" : [
  26. "2020-04-30T19:31:22.000Z"
  27. ]
  28. }
  29. }
  30. ]
  31. }
  32. }