eql.asciidoc 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890
  1. [role="xpack"]
  2. [[eql]]
  3. = EQL search
  4. ++++
  5. <titleabbrev>EQL</titleabbrev>
  6. ++++
  7. Event Query Language (EQL) is a query language for event-based time series
  8. data, such as logs, metrics, and traces.
  9. [discrete]
  10. [[eql-advantages]]
  11. === Advantages of EQL
  12. * *EQL lets you express relationships between events.* +
  13. Many query languages allow you to match single events. EQL lets you match a
  14. sequence of events across different event categories and time spans.
  15. * *EQL has a low learning curve.* +
  16. <<eql-syntax,EQL syntax>> looks like other common query languages, such as SQL.
  17. EQL lets you write and read queries intuitively, which makes for quick,
  18. iterative searching.
  19. * *EQL is designed for security use cases.* +
  20. While you can use it for any event-based data, we created EQL for threat
  21. hunting. EQL not only supports indicator of compromise (IOC) searches but can
  22. describe activity that goes beyond IOCs.
  23. [discrete]
  24. [[eql-required-fields]]
  25. === Required fields
  26. To run an EQL search, the searched data stream or index must contain a
  27. _timestamp_ and _event category_ field. By default, EQL uses the `@timestamp`
  28. and `event.category` fields from the {ecs-ref}[Elastic Common Schema
  29. (ECS)]. To use a different timestamp or event category field, see
  30. <<specify-a-timestamp-or-event-category-field>>.
  31. TIP: While no schema is required to use EQL, we recommend using the
  32. {ecs-ref}[ECS]. EQL searches are designed to work with core ECS fields by
  33. default.
  34. [discrete]
  35. [[run-an-eql-search]]
  36. === Run an EQL search
  37. Use the <<eql-search-api,EQL search API>> to run a <<eql-basic-syntax,basic EQL
  38. query>>.
  39. ////
  40. [source,console]
  41. ----
  42. DELETE /_data_stream/*
  43. DELETE /_index_template/*
  44. ----
  45. // TEARDOWN
  46. ////
  47. [source,console]
  48. ----
  49. GET /my-data-stream/_eql/search
  50. {
  51. "query": """
  52. process where process.name == "regsvr32.exe"
  53. """
  54. }
  55. ----
  56. // TEST[setup:sec_logs]
  57. By default, basic EQL queries return the 10 most recent matching events in the
  58. `hits.events` property. These hits are sorted by timestamp, converted to
  59. milliseconds since the {wikipedia}/Unix_time[Unix epoch], in ascending order.
  60. [source,console-result]
  61. ----
  62. {
  63. "is_partial": false,
  64. "is_running": false,
  65. "took": 60,
  66. "timed_out": false,
  67. "hits": {
  68. "total": {
  69. "value": 2,
  70. "relation": "eq"
  71. },
  72. "events": [
  73. {
  74. "_index": ".ds-my-data-stream-2099.12.07-000001",
  75. "_id": "OQmfCaduce8zoHT93o4H",
  76. "_source": {
  77. "@timestamp": "2099-12-07T11:07:09.000Z",
  78. "event": {
  79. "category": "process",
  80. "id": "aR3NWVOs",
  81. "sequence": 4
  82. },
  83. "process": {
  84. "pid": 2012,
  85. "name": "regsvr32.exe",
  86. "command_line": "regsvr32.exe /s /u /i:https://...RegSvr32.sct scrobj.dll",
  87. "executable": "C:\\Windows\\System32\\regsvr32.exe"
  88. }
  89. }
  90. },
  91. {
  92. "_index": ".ds-my-data-stream-2099.12.07-000001",
  93. "_id": "xLkCaj4EujzdNSxfYLbO",
  94. "_source": {
  95. "@timestamp": "2099-12-07T11:07:10.000Z",
  96. "event": {
  97. "category": "process",
  98. "id": "GTSmSqgz0U",
  99. "sequence": 6,
  100. "type": "termination"
  101. },
  102. "process": {
  103. "pid": 2012,
  104. "name": "regsvr32.exe",
  105. "executable": "C:\\Windows\\System32\\regsvr32.exe"
  106. }
  107. }
  108. }
  109. ]
  110. }
  111. }
  112. ----
  113. // TESTRESPONSE[s/"took": 60/"took": $body.took/]
  114. // TESTRESPONSE[s/"_index": ".ds-my-data-stream-2099.12.07-000001"/"_index": $body.hits.events.0._index/]
  115. // TESTRESPONSE[s/"_id": "OQmfCaduce8zoHT93o4H"/"_id": $body.hits.events.0._id/]
  116. // TESTRESPONSE[s/"_id": "xLkCaj4EujzdNSxfYLbO"/"_id": $body.hits.events.1._id/]
  117. Use the `size` parameter to get a smaller or larger set of hits:
  118. [source,console]
  119. ----
  120. GET /my-data-stream/_eql/search
  121. {
  122. "query": """
  123. process where process.name == "regsvr32.exe"
  124. """,
  125. "size": 50
  126. }
  127. ----
  128. // TEST[setup:sec_logs]
  129. [discrete]
  130. [[eql-search-sequence]]
  131. === Search for a sequence of events
  132. Use EQL's <<eql-sequences,sequence syntax>> to search for a series of
  133. ordered events. List the event items in ascending chronological order,
  134. with the most recent event listed last:
  135. [source,console]
  136. ----
  137. GET /my-data-stream/_eql/search
  138. {
  139. "query": """
  140. sequence
  141. [ process where process.name == "regsvr32.exe" ]
  142. [ file where stringContains(file.name, "scrobj.dll") ]
  143. """
  144. }
  145. ----
  146. // TEST[setup:sec_logs]
  147. The response's `hits.sequences` property contains the 10 most recent matching
  148. sequences.
  149. [source,console-result]
  150. ----
  151. {
  152. ...
  153. "hits": {
  154. "total": ...,
  155. "sequences": [
  156. {
  157. "events": [
  158. {
  159. "_index": ".ds-my-data-stream-2099.12.07-000001",
  160. "_id": "OQmfCaduce8zoHT93o4H",
  161. "_source": {
  162. "@timestamp": "2099-12-07T11:07:09.000Z",
  163. "event": {
  164. "category": "process",
  165. "id": "aR3NWVOs",
  166. "sequence": 4
  167. },
  168. "process": {
  169. "pid": 2012,
  170. "name": "regsvr32.exe",
  171. "command_line": "regsvr32.exe /s /u /i:https://...RegSvr32.sct scrobj.dll",
  172. "executable": "C:\\Windows\\System32\\regsvr32.exe"
  173. }
  174. }
  175. },
  176. {
  177. "_index": ".ds-my-data-stream-2099.12.07-000001",
  178. "_id": "yDwnGIJouOYGBzP0ZE9n",
  179. "_source": {
  180. "@timestamp": "2099-12-07T11:07:10.000Z",
  181. "event": {
  182. "category": "file",
  183. "id": "tZ1NWVOs",
  184. "sequence": 5
  185. },
  186. "process": {
  187. "pid": 2012,
  188. "name": "regsvr32.exe",
  189. "executable": "C:\\Windows\\System32\\regsvr32.exe"
  190. },
  191. "file": {
  192. "path": "C:\\Windows\\System32\\scrobj.dll",
  193. "name": "scrobj.dll"
  194. }
  195. }
  196. }
  197. ]
  198. }
  199. ]
  200. }
  201. }
  202. ----
  203. // TESTRESPONSE[s/ \.\.\.\n/"is_partial": false, "is_running": false, "took": $body.took, "timed_out": false,/]
  204. // TESTRESPONSE[s/"total": \.\.\.,/"total": { "value": 1, "relation": "eq" },/]
  205. // TESTRESPONSE[s/"_index": ".ds-my-data-stream-2099.12.07-000001"/"_index": $body.hits.sequences.0.events.0._index/]
  206. // TESTRESPONSE[s/"_id": "OQmfCaduce8zoHT93o4H"/"_id": $body.hits.sequences.0.events.0._id/]
  207. // TESTRESPONSE[s/"_id": "yDwnGIJouOYGBzP0ZE9n"/"_id": $body.hits.sequences.0.events.1._id/]
  208. Use <<eql-with-maxspan-keywords,`with maxspan`>> to constrain matching sequences
  209. to a timespan:
  210. [source,console]
  211. ----
  212. GET /my-data-stream/_eql/search
  213. {
  214. "query": """
  215. sequence with maxspan=1h
  216. [ process where process.name == "regsvr32.exe" ]
  217. [ file where stringContains(file.name, "scrobj.dll") ]
  218. """
  219. }
  220. ----
  221. // TEST[setup:sec_logs]
  222. Use the <<eql-by-keyword,`by` keyword>> to match events that share the
  223. same field values:
  224. [source,console]
  225. ----
  226. GET /my-data-stream/_eql/search
  227. {
  228. "query": """
  229. sequence with maxspan=1h
  230. [ process where process.name == "regsvr32.exe" ] by process.pid
  231. [ file where stringContains(file.name, "scrobj.dll") ] by process.pid
  232. """
  233. }
  234. ----
  235. // TEST[setup:sec_logs]
  236. If a field value should be shared across all events, use the `sequence by`
  237. keyword. The following query is equivalent to the previous one.
  238. [source,console]
  239. ----
  240. GET /my-data-stream/_eql/search
  241. {
  242. "query": """
  243. sequence by process.pid with maxspan=1h
  244. [ process where process.name == "regsvr32.exe" ]
  245. [ file where stringContains(file.name, "scrobj.dll") ]
  246. """
  247. }
  248. ----
  249. // TEST[setup:sec_logs]
  250. The `hits.sequences.join_keys` property contains the shared field values.
  251. [source,console-result]
  252. ----
  253. {
  254. ...
  255. "hits": ...,
  256. "sequences": [
  257. {
  258. "join_keys": [
  259. 2012
  260. ],
  261. "events": ...
  262. }
  263. ]
  264. }
  265. }
  266. ----
  267. // TESTRESPONSE[s/ \.\.\.\n/"is_partial": false, "is_running": false, "took": $body.took, "timed_out": false,/]
  268. // TESTRESPONSE[s/"hits": \.\.\.,/"hits": { "total": { "value": 1, "relation": "eq" },/]
  269. // TESTRESPONSE[s/"events": \.\.\./"events": $body.hits.sequences.0.events/]
  270. Use the <<eql-until-keyword,`until` keyword>> to specify an expiration
  271. event for sequences. Matching sequences must end before this event.
  272. [source,console]
  273. ----
  274. GET /my-data-stream/_eql/search
  275. {
  276. "query": """
  277. sequence by process.pid with maxspan=1h
  278. [ process where process.name == "regsvr32.exe" ]
  279. [ file where stringContains(file.name, "scrobj.dll") ]
  280. until [ process where event.type == "termination" ]
  281. """
  282. }
  283. ----
  284. // TEST[setup:sec_logs]
  285. [discrete]
  286. [[retrieve-selected-fields]]
  287. === Retrieve selected fields
  288. By default, each hit in the search response includes the document `_source`,
  289. which is the entire JSON object that was provided when indexing the document.
  290. You can use the <<common-options-response-filtering,`filter_path`>> query
  291. parameter to filter the API response. For example, the following search returns
  292. only the timestamp and PID from the `_source` of each matching event.
  293. [source,console]
  294. ----
  295. GET /my-data-stream/_eql/search?filter_path=hits.events._source.@timestamp,hits.events._source.process.pid
  296. {
  297. "query": """
  298. process where process.name == "regsvr32.exe"
  299. """
  300. }
  301. ----
  302. // TEST[setup:sec_logs]
  303. The API returns the following response.
  304. [source,console-result]
  305. ----
  306. {
  307. "hits": {
  308. "events": [
  309. {
  310. "_source": {
  311. "@timestamp": "2099-12-07T11:07:09.000Z",
  312. "process": {
  313. "pid": 2012
  314. }
  315. }
  316. },
  317. {
  318. "_source": {
  319. "@timestamp": "2099-12-07T11:07:10.000Z",
  320. "process": {
  321. "pid": 2012
  322. }
  323. }
  324. }
  325. ]
  326. }
  327. }
  328. ----
  329. You can also use the `fields` parameter to retrieve and format specific fields
  330. in the response. This field is identical to the search API's
  331. <<search-fields,`fields` parameter>>.
  332. include::{es-repo-dir}/search/search-your-data/retrieve-selected-fields.asciidoc[tag=fields-param-desc]
  333. The following search request uses the `fields` parameter to retrieve values for
  334. the `event.type` field, all fields starting with `process.`, and the
  335. `@timestamp` field. The request also uses the `filter_path` query parameter to
  336. exclude the `_source` of each hit.
  337. [source,console]
  338. ----
  339. GET /my-data-stream/_eql/search?filter_path=-hits.events._source
  340. {
  341. "query": """
  342. process where process.name == "regsvr32.exe"
  343. """,
  344. "fields": [
  345. "event.type",
  346. "process.*", <1>
  347. {
  348. "field": "@timestamp",
  349. "format": "epoch_millis" <2>
  350. }
  351. ]
  352. }
  353. ----
  354. // TEST[setup:sec_logs]
  355. include::{es-repo-dir}/search/search-your-data/retrieve-selected-fields.asciidoc[tag=fields-param-callouts]
  356. The response includes values as a flat list in the `fields` section for each
  357. hit.
  358. [source,console-result]
  359. ----
  360. {
  361. ...
  362. "hits": {
  363. "total": ...,
  364. "events": [
  365. {
  366. "_index": ".ds-my-data-stream-2099.12.07-000001",
  367. "_id": "OQmfCaduce8zoHT93o4H",
  368. "fields": {
  369. "process.name": [
  370. "regsvr32.exe"
  371. ],
  372. "process.name.keyword": [
  373. "regsvr32.exe"
  374. ],
  375. "@timestamp": [
  376. "4100324829000"
  377. ],
  378. "process.command_line": [
  379. "regsvr32.exe /s /u /i:https://...RegSvr32.sct scrobj.dll"
  380. ],
  381. "process.command_line.keyword": [
  382. "regsvr32.exe /s /u /i:https://...RegSvr32.sct scrobj.dll"
  383. ],
  384. "process.executable.keyword": [
  385. "C:\\Windows\\System32\\regsvr32.exe"
  386. ],
  387. "process.pid": [
  388. 2012
  389. ],
  390. "process.executable": [
  391. "C:\\Windows\\System32\\regsvr32.exe"
  392. ]
  393. }
  394. },
  395. ....
  396. ]
  397. }
  398. }
  399. ----
  400. // TESTRESPONSE[s/ \.\.\.\n/"is_partial": false, "is_running": false, "took": $body.took, "timed_out": false,/]
  401. // TESTRESPONSE[s/"total": \.\.\.,/"total": { "value": 2, "relation": "eq" },/]
  402. // TESTRESPONSE[s/"_index": ".ds-my-data-stream-2099.12.07-000001"/"_index": $body.hits.events.0._index/]
  403. // TESTRESPONSE[s/"_id": "OQmfCaduce8zoHT93o4H"/"_id": $body.hits.events.0._id/]
  404. // TESTRESPONSE[s/ \.\.\.\.\n/$body.hits.events.1/]
  405. [discrete]
  406. [[eql-use-runtime-fields]]
  407. === Use runtime fields
  408. Use the `runtime_mappings` parameter to extract and create <<runtime,runtime
  409. fields>> during a search. Use the `fields` parameter to include runtime fields
  410. in the response.
  411. The following search creates a `day_of_week` runtime field from the `@timestamp`
  412. and returns it in the response.
  413. [source,console]
  414. ----
  415. GET /my-data-stream/_eql/search?filter_path=-hits.events._source
  416. {
  417. "runtime_mappings": {
  418. "day_of_week": {
  419. "type": "keyword",
  420. "script": "emit(doc['@timestamp'].value.dayOfWeekEnum.toString())"
  421. }
  422. },
  423. "query": """
  424. process where process.name == "regsvr32.exe"
  425. """,
  426. "fields": [
  427. "@timestamp",
  428. "day_of_week"
  429. ]
  430. }
  431. ----
  432. // TEST[setup:sec_logs]
  433. The API returns:
  434. [source,console-result]
  435. ----
  436. {
  437. ...
  438. "hits": {
  439. "total": ...,
  440. "events": [
  441. {
  442. "_index": ".ds-my-data-stream-2099.12.07-000001",
  443. "_id": "OQmfCaduce8zoHT93o4H",
  444. "fields": {
  445. "@timestamp": [
  446. "2099-12-07T11:07:09.000Z"
  447. ],
  448. "day_of_week": [
  449. "MONDAY"
  450. ]
  451. }
  452. },
  453. ....
  454. ]
  455. }
  456. }
  457. ----
  458. // TESTRESPONSE[s/ \.\.\.\n/"is_partial": false, "is_running": false, "took": $body.took, "timed_out": false,/]
  459. // TESTRESPONSE[s/"total": \.\.\.,/"total": { "value": 2, "relation": "eq" },/]
  460. // TESTRESPONSE[s/"_index": ".ds-my-data-stream-2099.12.07-000001"/"_index": $body.hits.events.0._index/]
  461. // TESTRESPONSE[s/"_id": "OQmfCaduce8zoHT93o4H"/"_id": $body.hits.events.0._id/]
  462. // TESTRESPONSE[s/ \.\.\.\.\n/$body.hits.events.1/]
  463. [discrete]
  464. [[specify-a-timestamp-or-event-category-field]]
  465. === Specify a timestamp or event category field
  466. The EQL search API uses the `@timestamp` and `event.category` fields from the
  467. {ecs-ref}[ECS] by default. To specify different fields, use the
  468. `timestamp_field` and `event_category_field` parameters:
  469. [source,console]
  470. ----
  471. GET /my-data-stream/_eql/search
  472. {
  473. "timestamp_field": "file.accessed",
  474. "event_category_field": "file.type",
  475. "query": """
  476. file where (file.size > 1 and file.type == "file")
  477. """
  478. }
  479. ----
  480. // TEST[setup:sec_logs]
  481. The event category field must be mapped as a <<keyword,`keyword`>> family field
  482. type. The timestamp field should be mapped as a <<date,`date`>> field type.
  483. <<date_nanos,`date_nanos`>> timestamp fields are not supported. You cannot use a
  484. <<nested,`nested`>> field or the sub-fields of a `nested` field as the timestamp
  485. or event category field.
  486. [discrete]
  487. [[eql-search-specify-a-sort-tiebreaker]]
  488. === Specify a sort tiebreaker
  489. By default, the EQL search API returns matching hits by timestamp. If two or
  490. more events share the same timestamp, {es} uses a tiebreaker field value to sort
  491. the events in ascending order. {es} orders events with no
  492. tiebreaker value after events with a value.
  493. If you don't specify a tiebreaker field or the events also share the same
  494. tiebreaker value, {es} considers the events concurrent and may
  495. not return them in a consistent sort order.
  496. To specify a tiebreaker field, use the `tiebreaker_field` parameter. If you use
  497. the {ecs-ref}[ECS], we recommend using `event.sequence` as the tiebreaker field.
  498. [source,console]
  499. ----
  500. GET /my-data-stream/_eql/search
  501. {
  502. "tiebreaker_field": "event.sequence",
  503. "query": """
  504. process where process.name == "cmd.exe" and stringContains(process.executable, "System32")
  505. """
  506. }
  507. ----
  508. // TEST[setup:sec_logs]
  509. [discrete]
  510. [[eql-search-filter-query-dsl]]
  511. === Filter using Query DSL
  512. The `filter` parameter uses <<query-dsl,Query DSL>> to limit the documents on
  513. which an EQL query runs.
  514. [source,console]
  515. ----
  516. GET /my-data-stream/_eql/search
  517. {
  518. "filter": {
  519. "range": {
  520. "@timestamp": {
  521. "gte": "now-1d/d",
  522. "lt": "now/d"
  523. }
  524. }
  525. },
  526. "query": """
  527. file where (file.type == "file" and file.name == "cmd.exe")
  528. """
  529. }
  530. ----
  531. // TEST[setup:sec_logs]
  532. [discrete]
  533. [[eql-search-async]]
  534. === Run an async EQL search
  535. By default, EQL search requests are synchronous and wait for complete results
  536. before returning a response. However, complete results can take longer for
  537. searches across large data sets or <<data-tiers,frozen>> data.
  538. To avoid long waits, run an async EQL search. Set `wait_for_completion_timeout`
  539. to a duration you'd like to wait for synchronous results.
  540. [source,console]
  541. ----
  542. GET /my-data-stream/_eql/search
  543. {
  544. "wait_for_completion_timeout": "2s",
  545. "query": """
  546. process where process.name == "cmd.exe"
  547. """
  548. }
  549. ----
  550. // TEST[setup:sec_logs]
  551. If the request doesn't finish within the timeout period, the search becomes async
  552. and returns a response that includes:
  553. * A search ID
  554. * An `is_partial` value of `true`, indicating the search results are
  555. incomplete
  556. * An `is_running` value of `true`, indicating the search is ongoing
  557. The async search continues to run in the background without blocking other
  558. requests.
  559. [source,console-result]
  560. ----
  561. {
  562. "id": "FmNJRUZ1YWZCU3dHY1BIOUhaenVSRkEaaXFlZ3h4c1RTWFNocDdnY2FSaERnUTozNDE=",
  563. "is_partial": true,
  564. "is_running": true,
  565. "took": 2000,
  566. "timed_out": false,
  567. "hits": ...
  568. }
  569. ----
  570. // TESTRESPONSE[s/FmNJRUZ1YWZCU3dHY1BIOUhaenVSRkEaaXFlZ3h4c1RTWFNocDdnY2FSaERnUTozNDE=/$body.id/]
  571. // TESTRESPONSE[s/"is_partial": true/"is_partial": $body.is_partial/]
  572. // TESTRESPONSE[s/"is_running": true/"is_running": $body.is_running/]
  573. // TESTRESPONSE[s/"took": 2000/"took": $body.took/]
  574. // TESTRESPONSE[s/"hits": \.\.\./"hits": $body.hits/]
  575. To check the progress of an async search, use the <<get-async-eql-search-api,get
  576. async EQL search API>> with the search ID. Specify how long you'd like for
  577. complete results in the `wait_for_completion_timeout` parameter.
  578. [source,console]
  579. ----
  580. GET /_eql/search/FmNJRUZ1YWZCU3dHY1BIOUhaenVSRkEaaXFlZ3h4c1RTWFNocDdnY2FSaERnUTozNDE=?wait_for_completion_timeout=2s
  581. ----
  582. // TEST[skip: no access to search ID]
  583. If the response's `is_running` value is `false`, the async search has finished.
  584. If the `is_partial` value is `false`, the returned search results are
  585. complete.
  586. [source,console-result]
  587. ----
  588. {
  589. "id": "FmNJRUZ1YWZCU3dHY1BIOUhaenVSRkEaaXFlZ3h4c1RTWFNocDdnY2FSaERnUTozNDE=",
  590. "is_partial": false,
  591. "is_running": false,
  592. "took": 2000,
  593. "timed_out": false,
  594. "hits": ...
  595. }
  596. ----
  597. // TESTRESPONSE[s/FmNJRUZ1YWZCU3dHY1BIOUhaenVSRkEaaXFlZ3h4c1RTWFNocDdnY2FSaERnUTozNDE=/$body.id/]
  598. // TESTRESPONSE[s/"took": 2000/"took": $body.took/]
  599. // TESTRESPONSE[s/"hits": \.\.\./"hits": $body.hits/]
  600. Another more lightweight way to check the progress of an async search is to use
  601. the <<get-async-eql-status-api,get async EQL status API>> with the search ID.
  602. [source,console]
  603. ----
  604. GET /_eql/search/status/FmNJRUZ1YWZCU3dHY1BIOUhaenVSRkEaaXFlZ3h4c1RTWFNocDdnY2FSaERnUTozNDE=
  605. ----
  606. // TEST[skip: no access to search ID]
  607. [source,console-result]
  608. ----
  609. {
  610. "id": "FmNJRUZ1YWZCU3dHY1BIOUhaenVSRkEaaXFlZ3h4c1RTWFNocDdnY2FSaERnUTozNDE=",
  611. "is_running": false,
  612. "is_partial": false,
  613. "expiration_time_in_millis": 1611690295000,
  614. "completion_status": 200
  615. }
  616. ----
  617. // TESTRESPONSE[s/FmNJRUZ1YWZCU3dHY1BIOUhaenVSRkEaaXFlZ3h4c1RTWFNocDdnY2FSaERnUTozNDE=/$body.id/]
  618. // TESTRESPONSE[s/"expiration_time_in_millis": 1611690295000/"expiration_time_in_millis": $body.expiration_time_in_millis/]
  619. [discrete]
  620. [[eql-search-store-async-eql-search]]
  621. === Change the search retention period
  622. By default, the EQL search API stores async searches for five days. After this
  623. period, any searches and their results are deleted. Use the `keep_alive`
  624. parameter to change this retention period:
  625. [source,console]
  626. ----
  627. GET /my-data-stream/_eql/search
  628. {
  629. "keep_alive": "2d",
  630. "wait_for_completion_timeout": "2s",
  631. "query": """
  632. process where process.name == "cmd.exe"
  633. """
  634. }
  635. ----
  636. // TEST[setup:sec_logs]
  637. You can use the <<get-async-eql-search-api,get async EQL search API>>'s
  638. `keep_alive` parameter to later change the retention period. The new retention
  639. period starts after the get request runs.
  640. [source,console]
  641. ----
  642. GET /_eql/search/FmNJRUZ1YWZCU3dHY1BIOUhaenVSRkEaaXFlZ3h4c1RTWFNocDdnY2FSaERnUTozNDE=?keep_alive=5d
  643. ----
  644. // TEST[skip: no access to search ID]
  645. Use the <<delete-async-eql-search-api,delete async EQL search API>> to
  646. manually delete an async EQL search before the `keep_alive` period ends. If the
  647. search is still ongoing, {es} cancels the search request.
  648. [source,console]
  649. ----
  650. DELETE /_eql/search/FmNJRUZ1YWZCU3dHY1BIOUhaenVSRkEaaXFlZ3h4c1RTWFNocDdnY2FSaERnUTozNDE=
  651. ----
  652. // TEST[skip: no access to search ID]
  653. [discrete]
  654. [[eql-search-store-sync-eql-search]]
  655. === Store synchronous EQL searches
  656. By default, the EQL search API only stores async searches. To save a synchronous
  657. search, set `keep_on_completion` to `true`:
  658. [source,console]
  659. ----
  660. GET /my-data-stream/_eql/search
  661. {
  662. "keep_on_completion": true,
  663. "wait_for_completion_timeout": "2s",
  664. "query": """
  665. process where process.name == "cmd.exe"
  666. """
  667. }
  668. ----
  669. // TEST[setup:sec_logs]
  670. The response includes a search ID. `is_partial` and `is_running` are `false`,
  671. indicating the EQL search was synchronous and returned complete results.
  672. [source,console-result]
  673. ----
  674. {
  675. "id": "FjlmbndxNmJjU0RPdExBTGg0elNOOEEaQk9xSjJBQzBRMldZa1VVQ2pPa01YUToxMDY=",
  676. "is_partial": false,
  677. "is_running": false,
  678. "took": 52,
  679. "timed_out": false,
  680. "hits": ...
  681. }
  682. ----
  683. // TESTRESPONSE[s/FjlmbndxNmJjU0RPdExBTGg0elNOOEEaQk9xSjJBQzBRMldZa1VVQ2pPa01YUToxMDY=/$body.id/]
  684. // TESTRESPONSE[s/"took": 52/"took": $body.took/]
  685. // TESTRESPONSE[s/"hits": \.\.\./"hits": $body.hits/]
  686. Use the <<get-async-eql-search-api,get async EQL search API>> to get the
  687. same results later:
  688. [source,console]
  689. ----
  690. GET /_eql/search/FjlmbndxNmJjU0RPdExBTGg0elNOOEEaQk9xSjJBQzBRMldZa1VVQ2pPa01YUToxMDY=
  691. ----
  692. // TEST[skip: no access to search ID]
  693. Saved synchronous searches are still subject to the `keep_alive` parameter's
  694. retention period. When this period ends, the search and its results are deleted.
  695. You can also check only the status of the saved synchronous search without
  696. results by using <<get-async-eql-status-api,get async EQL status API>>.
  697. You can also manually delete saved synchronous searches using the
  698. <<delete-async-eql-search-api,delete async EQL search API>>.
  699. [discrete]
  700. [[run-eql-search-across-clusters]]
  701. === Run an EQL search across clusters
  702. experimental::[]
  703. The EQL search API supports <<modules-cross-cluster-search,cross-cluster
  704. search>>. However, the local and <<remote-clusters,remote clusters>>
  705. must use the same {es} version.
  706. The following <<cluster-update-settings,cluster update settings>> request
  707. adds two remote clusters: `cluster_one` and `cluster_two`.
  708. [source,console]
  709. ----
  710. PUT /_cluster/settings
  711. {
  712. "persistent": {
  713. "cluster": {
  714. "remote": {
  715. "cluster_one": {
  716. "seeds": [
  717. "127.0.0.1:9300"
  718. ]
  719. },
  720. "cluster_two": {
  721. "seeds": [
  722. "127.0.0.1:9301"
  723. ]
  724. }
  725. }
  726. }
  727. }
  728. }
  729. ----
  730. // TEST[setup:host]
  731. // TEST[s/127.0.0.1:930\d+/\${transport_host}/]
  732. To target a data stream or index on a remote cluster, use the
  733. `<cluster>:<target>` syntax.
  734. [source,console]
  735. ----
  736. GET /cluster_one:my-data-stream,cluster_two:my-data-stream/_eql/search
  737. {
  738. "query": """
  739. process where process.name == "regsvr32.exe"
  740. """
  741. }
  742. ----
  743. // TEST[continued]
  744. // TEST[setup:sec_logs]
  745. // TEST[teardown:data_stream_cleanup]
  746. [discrete]
  747. [[eql-circuit-breaker]]
  748. === EQL circuit breaker settings
  749. When a <<eql-sequences, sequence>> query is executed, the node handling the query
  750. needs to keep some structures in memory, which are needed by the algorithm
  751. implementing the sequence matching. When large amounts of data need to be processed,
  752. and/or a large amount of matched sequences is requested by the user (by setting the
  753. <<eql-search-api-params-size, size>> query param), the memory occupied by those
  754. structures could potentially exceed the available memory of the JVM. This would cause
  755. an `OutOfMemory` exception which would bring down the node.
  756. To prevent this from happening, a special <<circuit-breaker, circuit breaker>> is used,
  757. which limits the memory allocation during the execution of a <<eql-sequences, sequence>>
  758. query. When the breaker is triggered, an `org.elasticsearch.common.breaker.CircuitBreakingException`
  759. is thrown and a descriptive error message is returned to the user.
  760. This <<circuit-breaker, circuit breaker>> can be configured using the following settings:
  761. `breaker.eql_sequence.limit`::
  762. (<<cluster-update-settings,Dynamic>>) The limit for circuit breaker used to restrict
  763. the memory utilisation during the execution of an EQL sequence query. This value is
  764. defined as a percentage of the JVM heap. Defaults to `50%`. If the
  765. <<parent-circuit-breaker,parent circuit breaker>> is set to a value less than `50%`,
  766. this setting uses that value as its default instead.
  767. `breaker.eql_sequence.overhead`::
  768. (<<cluster-update-settings,Dynamic>>) A constant that sequence query memory
  769. estimates are multiplied by to determine a final estimate. Defaults to `1`.
  770. `breaker.eql_sequence.type`::
  771. (<<static-cluster-setting,Static>>) Circuit breaker type. Valid values are:
  772. `memory` (Default):::
  773. The breaker limits memory usage for EQL sequence queries.
  774. `noop`:::
  775. Disables the breaker.
  776. include::syntax.asciidoc[]
  777. include::functions.asciidoc[]
  778. include::pipes.asciidoc[]
  779. include::detect-threats-with-eql.asciidoc[]