eql.asciidoc 23 KB

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