eql.asciidoc 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741
  1. [role="xpack"]
  2. [testenv="basic"]
  3. [[eql]]
  4. = EQL search
  5. ++++
  6. <titleabbrev>EQL</titleabbrev>
  7. ++++
  8. experimental::[]
  9. {eql-ref}/index.html[Event Query Language (EQL)] is a query language for
  10. event-based, time series data, such as logs.
  11. [discrete]
  12. [[eql-advantages]]
  13. == Advantages of EQL
  14. * *EQL lets you express relationships between events.* +
  15. Many query languages allow you to match only single events. EQL lets you match a
  16. sequence of events across different event categories and time spans.
  17. * *EQL has a low learning curve.* +
  18. <<eql-syntax,EQL syntax>> looks like other query languages. It lets you write
  19. and read queries intuitively, which makes for quick, iterative searching.
  20. * *We designed EQL for security use cases.* +
  21. While you can use EQL for any event-based data, we created EQL for threat
  22. hunting. EQL not only supports indicator of compromise (IOC) searching but
  23. makes it easy to describe activity that goes beyond IOCs.
  24. [discrete]
  25. [[eql-required-fields]]
  26. == Required fields
  27. TIP: While no schema is required to use EQL in {es}, we recommend using the
  28. {ecs-ref}[Elastic Common Schema (ECS)]. EQL search is designed to work
  29. with core ECS fields by default.
  30. EQL assumes each document in a data stream or index corresponds to an event. To
  31. run an EQL search, each document must contain a _timestamp_ and _event category_
  32. field.
  33. EQL uses the `@timestamp` and `event.category` fields from the {ecs-ref}[ECS] as
  34. the default timestamp and event category fields. If your documents use a
  35. different timestamp or event category field, you must specify it in the search
  36. request. See <<specify-a-timestamp-or-event-category-field>>.
  37. [discrete]
  38. [[run-an-eql-search]]
  39. == Run an EQL search
  40. You can use the <<eql-search-api,EQL search API>> to run an EQL search. For
  41. supported query syntax, see <<eql-syntax>>.
  42. The following request searches `my-index-000001` for events with an
  43. `event.category` of `process` and a `process.name` of `regsvr32.exe`. Each
  44. document in `my-index-000001` includes a `@timestamp` and `event.category`
  45. field.
  46. [source,console]
  47. ----
  48. GET /my-index-000001/_eql/search
  49. {
  50. "query": """
  51. process where process.name == "regsvr32.exe"
  52. """
  53. }
  54. ----
  55. // TEST[setup:sec_logs]
  56. By default, EQL searches return only the top 10 matching hits. For basic EQL
  57. queries, these hits are matching events and are included in the `hits.events`
  58. property. Matching events are sorted by timestamp, converted to milliseconds
  59. 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": "my-index-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": "my-index-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/"_id": "OQmfCaduce8zoHT93o4H"/"_id": $body.hits.events.0._id/]
  115. // TESTRESPONSE[s/"_id": "xLkCaj4EujzdNSxfYLbO"/"_id": $body.hits.events.1._id/]
  116. You can use the `size` request body parameter to get a larger or smaller set of
  117. hits. For example, the following request retrieves up to `50` matching hits.
  118. [source,console]
  119. ----
  120. GET /my-index-000001/_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. You can use EQL's <<eql-sequences,sequence syntax>> to search for an ordered
  133. series of events.
  134. The following EQL search request matches a sequence that:
  135. . Starts with an event with:
  136. +
  137. --
  138. * An `event.category` of `process`
  139. * A `process.name` of `regsvr32.exe`
  140. --
  141. . Followed by an event with:
  142. +
  143. --
  144. * An `event.category` of `file`
  145. * A `file.name` that contains the substring `scrobj.dll`
  146. --
  147. [source,console]
  148. ----
  149. GET /my-index-000001/_eql/search
  150. {
  151. "query": """
  152. sequence
  153. [ process where process.name == "regsvr32.exe" ]
  154. [ file where stringContains(file.name, "scrobj.dll") ]
  155. """
  156. }
  157. ----
  158. // TEST[setup:sec_logs]
  159. Matching sequences are returned in the `hits.sequences` property.
  160. [source,console-result]
  161. ----
  162. {
  163. "is_partial": false,
  164. "is_running": false,
  165. "took": 60,
  166. "timed_out": false,
  167. "hits": {
  168. "total": {
  169. "value": 1,
  170. "relation": "eq"
  171. },
  172. "sequences": [
  173. {
  174. "events": [
  175. {
  176. "_index": "my-index-000001",
  177. "_id": "OQmfCaduce8zoHT93o4H",
  178. "_source": {
  179. "@timestamp": "2099-12-07T11:07:09.000Z",
  180. "event": {
  181. "category": "process",
  182. "id": "aR3NWVOs",
  183. "sequence": 4
  184. },
  185. "process": {
  186. "pid": 2012,
  187. "name": "regsvr32.exe",
  188. "command_line": "regsvr32.exe /s /u /i:https://...RegSvr32.sct scrobj.dll",
  189. "executable": "C:\\Windows\\System32\\regsvr32.exe"
  190. }
  191. }
  192. },
  193. {
  194. "_index": "my-index-000001",
  195. "_id": "yDwnGIJouOYGBzP0ZE9n",
  196. "_source": {
  197. "@timestamp": "2099-12-07T11:07:10.000Z",
  198. "event": {
  199. "category": "file",
  200. "id": "tZ1NWVOs",
  201. "sequence": 5
  202. },
  203. "process": {
  204. "pid": 2012,
  205. "name": "regsvr32.exe",
  206. "executable": "C:\\Windows\\System32\\regsvr32.exe"
  207. },
  208. "file": {
  209. "path": "C:\\Windows\\System32\\scrobj.dll",
  210. "name": "scrobj.dll"
  211. }
  212. }
  213. }
  214. ]
  215. }
  216. ]
  217. }
  218. }
  219. ----
  220. // TESTRESPONSE[s/"took": 60/"took": $body.took/]
  221. // TESTRESPONSE[s/"_id": "OQmfCaduce8zoHT93o4H"/"_id": $body.hits.sequences.0.events.0._id/]
  222. // TESTRESPONSE[s/"_id": "yDwnGIJouOYGBzP0ZE9n"/"_id": $body.hits.sequences.0.events.1._id/]
  223. You can use the <<eql-with-maxspan-keywords,`with maxspan` keywords>> to
  224. constrain a sequence to a specified timespan.
  225. The following EQL search request adds `with maxspan=1h` to the previous query.
  226. This ensures all events in a matching sequence occur within `1h` (one hour) of
  227. the first event's timestamp.
  228. [source,console]
  229. ----
  230. GET /my-index-000001/_eql/search
  231. {
  232. "query": """
  233. sequence with maxspan=1h
  234. [ process where process.name == "regsvr32.exe" ]
  235. [ file where stringContains(file.name, "scrobj.dll") ]
  236. """
  237. }
  238. ----
  239. // TEST[setup:sec_logs]
  240. You can further constrain matching event sequences using the
  241. <<eql-by-keyword,`by` keyword>>.
  242. The following EQL search request adds `by process.pid` to each event item. This
  243. ensures events matching the sequence share the same `process.pid` field value.
  244. [source,console]
  245. ----
  246. GET /my-index-000001/_eql/search
  247. {
  248. "query": """
  249. sequence with maxspan=1h
  250. [ process where process.name == "regsvr32.exe" ] by process.pid
  251. [ file where stringContains(file.name, "scrobj.dll") ] by process.pid
  252. """
  253. }
  254. ----
  255. // TEST[setup:sec_logs]
  256. Because the `process.pid` field is shared across all events in the sequence, it
  257. can be included using `sequence by`. The following query is equivalent to the
  258. previous one.
  259. [source,console]
  260. ----
  261. GET /my-index-000001/_eql/search
  262. {
  263. "query": """
  264. sequence by process.pid with maxspan=1h
  265. [ process where process.name == "regsvr32.exe" ]
  266. [ file where stringContains(file.name, "scrobj.dll") ]
  267. """
  268. }
  269. ----
  270. // TEST[setup:sec_logs]
  271. The API returns the following response. The `hits.sequences.join_keys` property
  272. contains the shared `process.pid` value for each matching event.
  273. [source,console-result]
  274. ----
  275. {
  276. "is_partial": false,
  277. "is_running": false,
  278. "took": 60,
  279. "timed_out": false,
  280. "hits": {
  281. "total": {
  282. "value": 1,
  283. "relation": "eq"
  284. },
  285. "sequences": [
  286. {
  287. "join_keys": [
  288. 2012
  289. ],
  290. "events": [
  291. {
  292. "_index": "my-index-000001",
  293. "_id": "OQmfCaduce8zoHT93o4H",
  294. "_source": {
  295. "@timestamp": "2099-12-07T11:07:09.000Z",
  296. "event": {
  297. "category": "process",
  298. "id": "aR3NWVOs",
  299. "sequence": 4
  300. },
  301. "process": {
  302. "pid": 2012,
  303. "name": "regsvr32.exe",
  304. "command_line": "regsvr32.exe /s /u /i:https://...RegSvr32.sct scrobj.dll",
  305. "executable": "C:\\Windows\\System32\\regsvr32.exe"
  306. }
  307. }
  308. },
  309. {
  310. "_index": "my-index-000001",
  311. "_id": "yDwnGIJouOYGBzP0ZE9n",
  312. "_source": {
  313. "@timestamp": "2099-12-07T11:07:10.000Z",
  314. "event": {
  315. "category": "file",
  316. "id": "tZ1NWVOs",
  317. "sequence": 5
  318. },
  319. "process": {
  320. "pid": 2012,
  321. "name": "regsvr32.exe",
  322. "executable": "C:\\Windows\\System32\\regsvr32.exe"
  323. },
  324. "file": {
  325. "path": "C:\\Windows\\System32\\scrobj.dll",
  326. "name": "scrobj.dll"
  327. }
  328. }
  329. }
  330. ]
  331. }
  332. ]
  333. }
  334. }
  335. ----
  336. // TESTRESPONSE[s/"took": 60/"took": $body.took/]
  337. // TESTRESPONSE[s/"_id": "OQmfCaduce8zoHT93o4H"/"_id": $body.hits.sequences.0.events.0._id/]
  338. // TESTRESPONSE[s/"_id": "yDwnGIJouOYGBzP0ZE9n"/"_id": $body.hits.sequences.0.events.1._id/]
  339. You can use the <<eql-until-keyword,`until` keyword>> to specify an expiration
  340. event for sequences. Matching sequences must end before this event.
  341. The following request adds `until [ process where event.type == "termination" ]`
  342. to the previous query. This ensures matching sequences end before a `process`
  343. event with an `event.type` of `termination`.
  344. [source,console]
  345. ----
  346. GET /my-index-000001/_eql/search
  347. {
  348. "query": """
  349. sequence by process.pid with maxspan=1h
  350. [ process where process.name == "regsvr32.exe" ]
  351. [ file where stringContains(file.name, "scrobj.dll") ]
  352. until [ process where event.type == "termination" ]
  353. """
  354. }
  355. ----
  356. // TEST[setup:sec_logs]
  357. [discrete]
  358. [[specify-a-timestamp-or-event-category-field]]
  359. === Specify a timestamp or event category field
  360. To run an EQL search, each searched document must contain a timestamp and event
  361. category field. The EQL search API uses the `@timestamp` and `event.category`
  362. fields from the {ecs-ref}[Elastic Common Schema (ECS)] by default. If your
  363. documents use a different timestamp or event category field, you must specify it
  364. in the search request using the `timestamp_field` or `event_category_field`
  365. parameters.
  366. The event category field must be mapped as a field type in the
  367. <<keyword,`keyword`>> family. The timestamp field should be mapped as a
  368. <<date,`date`>> field type. <<date_nanos,`date_nanos`>> timestamp fields are not
  369. supported.
  370. NOTE: You cannot use a <<nested,`nested`>> field or the sub-fields of a `nested`
  371. field as the timestamp or event category field. See <<eql-nested-fields>>.
  372. The following request uses the `timestamp_field` parameter to specify
  373. `file.accessed` as the timestamp field. The request also uses the
  374. `event_category_field` parameter to specify `file.type` as the event category
  375. field.
  376. [source,console]
  377. ----
  378. GET /my-index-000001/_eql/search
  379. {
  380. "timestamp_field": "file.accessed",
  381. "event_category_field": "file.type",
  382. "query": """
  383. file where (file.size > 1 and file.type == "file")
  384. """
  385. }
  386. ----
  387. // TEST[setup:sec_logs]
  388. [discrete]
  389. [[eql-search-specify-a-sort-tiebreaker]]
  390. === Specify a sort tiebreaker
  391. By default, the EQL search API sorts matching hits in the search response by
  392. timestamp. However, if two or more events share the same timestamp, you can use
  393. a tiebreaker field to sort the events in ascending, lexicographic order.
  394. The EQL search API uses `event.sequence` as the default tiebreaker field. You
  395. can use the `tiebreaker_field` parameter to specify another field.
  396. The following request specifies `event.id` as the tiebreaker field.
  397. [source,console]
  398. ----
  399. GET /my-index-000001/_eql/search
  400. {
  401. "tiebreaker_field": "event.id",
  402. "query": """
  403. process where process.name == "cmd.exe" and stringContains(process.executable, "System32")
  404. """
  405. }
  406. ----
  407. // TEST[setup:sec_logs]
  408. [discrete]
  409. [[eql-search-filter-query-dsl]]
  410. === Filter using query DSL
  411. You can use the `filter` parameter to specify an additional query using
  412. <<query-dsl,query DSL>>. This query filters the documents on which the EQL query
  413. runs.
  414. The following request uses a `range` query to filter `my-index-000001` to only
  415. documents with a `file.size` value greater than `1` but less than `1000000`
  416. bytes. The EQL query in `query` parameter then runs on these filtered documents.
  417. [source,console]
  418. ----
  419. GET /my-index-000001/_eql/search
  420. {
  421. "filter": {
  422. "range" : {
  423. "file.size" : {
  424. "gte" : 1,
  425. "lte" : 1000000
  426. }
  427. }
  428. },
  429. "query": """
  430. file where (file.type == "file" and file.name == "cmd.exe")
  431. """
  432. }
  433. ----
  434. // TEST[setup:sec_logs]
  435. [discrete]
  436. [[eql-search-case-sensitive]]
  437. === Run a case-sensitive EQL search
  438. By default, matching for EQL queries is case-insensitive. You can use the
  439. `case_sensitive` parameter to toggle case sensitivity on or off.
  440. The following search request contains a query that matches `process` events
  441. with a `process.executable` containing `System32`.
  442. Because `case_sensitive` is `true`, this query only matches `process.executable`
  443. values containing `System32` with the exact same capitalization. A
  444. `process.executable` value containing `system32` or `SYSTEM32` would not match
  445. this query.
  446. [source,console]
  447. ----
  448. GET /my-index-000001/_eql/search
  449. {
  450. "keep_on_completion": true,
  451. "case_sensitive": true,
  452. "query": """
  453. process where stringContains(process.executable, "System32")
  454. """
  455. }
  456. ----
  457. // TEST[setup:sec_logs]
  458. [discrete]
  459. [[eql-search-async]]
  460. === Run an async EQL search
  461. EQL searches are designed to run on large volumes of data quickly, often
  462. returning results in milliseconds. For this reason, EQL searches are
  463. _synchronous_ by default. The search request waits for complete results before
  464. returning a response.
  465. However, complete results can take longer for searches across:
  466. * <<frozen-indices,Frozen indices>>
  467. * <<modules-cross-cluster-search,Multiple clusters>>
  468. * Many shards
  469. To avoid long waits, you can use the `wait_for_completion_timeout` parameter to
  470. run an _asynchronous_, or _async_, EQL search.
  471. Set `wait_for_completion_timeout` to a duration you'd like to wait
  472. for complete search results. If the search request does not finish within this
  473. period, the search becomes async and returns a response that includes:
  474. * A search ID, which can be used to monitor the progress of the async search.
  475. * An `is_partial` value of `true`, meaning the response does not contain
  476. complete search results.
  477. * An `is_running` value of `true`, meaning the search is async and ongoing.
  478. The async search continues to run in the background without blocking
  479. other requests.
  480. The following request searches the `frozen-my-index-000001` index, which has been
  481. <<frozen-indices,frozen>> for storage and is rarely searched.
  482. Because searches on frozen indices are expected to take longer to complete, the
  483. request contains a `wait_for_completion_timeout` parameter value of `2s` (two
  484. seconds). If the request does not return complete results in two seconds, the
  485. search becomes async and returns a search ID.
  486. [source,console]
  487. ----
  488. GET /frozen-my-index-000001/_eql/search
  489. {
  490. "wait_for_completion_timeout": "2s",
  491. "query": """
  492. process where process.name == "cmd.exe"
  493. """
  494. }
  495. ----
  496. // TEST[setup:sec_logs]
  497. // TEST[s/frozen-my-index-000001/my-index-000001/]
  498. After two seconds, the request returns the following response. Note `is_partial`
  499. and `is_running` properties are `true`, indicating an async search.
  500. [source,console-result]
  501. ----
  502. {
  503. "id": "FmNJRUZ1YWZCU3dHY1BIOUhaenVSRkEaaXFlZ3h4c1RTWFNocDdnY2FSaERnUTozNDE=",
  504. "is_partial": true,
  505. "is_running": true,
  506. "took": 2000,
  507. "timed_out": false,
  508. "hits": ...
  509. }
  510. ----
  511. // TESTRESPONSE[s/FmNJRUZ1YWZCU3dHY1BIOUhaenVSRkEaaXFlZ3h4c1RTWFNocDdnY2FSaERnUTozNDE=/$body.id/]
  512. // TESTRESPONSE[s/"is_partial": true/"is_partial": $body.is_partial/]
  513. // TESTRESPONSE[s/"is_running": true/"is_running": $body.is_running/]
  514. // TESTRESPONSE[s/"took": 2000/"took": $body.took/]
  515. // TESTRESPONSE[s/"hits": \.\.\./"hits": $body.hits/]
  516. You can use the the search ID and the <<get-async-eql-search-api,get async EQL
  517. search API>> to check the progress of an async search.
  518. The get async EQL search API also accepts a `wait_for_completion_timeout`
  519. parameter. If ongoing search does not complete during this period, the response
  520. returns an `is_partial` value of `true` and no search results.
  521. The following get async EQL search API request checks the progress of the
  522. previous async EQL search. The request specifies a `wait_for_completion_timeout`
  523. query parameter value of `2s` (two seconds).
  524. [source,console]
  525. ----
  526. GET /_eql/search/FmNJRUZ1YWZCU3dHY1BIOUhaenVSRkEaaXFlZ3h4c1RTWFNocDdnY2FSaERnUTozNDE=?wait_for_completion_timeout=2s
  527. ----
  528. // TEST[skip: no access to search ID]
  529. The request returns the following response. Note `is_partial` and `is_running`
  530. are `false`, indicating the async search has finished and the search results
  531. in the `hits` property are complete.
  532. [source,console-result]
  533. ----
  534. {
  535. "id": "FmNJRUZ1YWZCU3dHY1BIOUhaenVSRkEaaXFlZ3h4c1RTWFNocDdnY2FSaERnUTozNDE=",
  536. "is_partial": false,
  537. "is_running": false,
  538. "took": 2000,
  539. "timed_out": false,
  540. "hits": ...
  541. }
  542. ----
  543. // TESTRESPONSE[s/FmNJRUZ1YWZCU3dHY1BIOUhaenVSRkEaaXFlZ3h4c1RTWFNocDdnY2FSaERnUTozNDE=/$body.id/]
  544. // TESTRESPONSE[s/"took": 2000/"took": $body.took/]
  545. // TESTRESPONSE[s/"hits": \.\.\./"hits": $body.hits/]
  546. [discrete]
  547. [[eql-search-store-async-eql-search]]
  548. === Change the search retention period
  549. By default, the EQL search API stores async searches for five days. After this
  550. period, any searches and their results are deleted. You can use the `keep_alive`
  551. parameter to change this retention period.
  552. In the following EQL search request, the `keep_alive` parameter is `2d` (two
  553. days). If the search becomes async, its results
  554. are stored on the cluster for two days. After two days, the async
  555. search and its results are deleted, even if it's still ongoing.
  556. [source,console]
  557. ----
  558. GET /my-index-000001/_eql/search
  559. {
  560. "keep_alive": "2d",
  561. "wait_for_completion_timeout": "2s",
  562. "query": """
  563. process where process.name == "cmd.exe"
  564. """
  565. }
  566. ----
  567. // TEST[setup:sec_logs]
  568. You can use the <<get-async-eql-search-api,get async EQL search API>>'s
  569. `keep_alive`parameter to later change the retention period. The new
  570. retention period starts after the get request executes.
  571. The following request sets the `keep_alive` query parameter to `5d` (five days).
  572. The async search and its results are deleted five days after the get request
  573. executes.
  574. [source,console]
  575. ----
  576. GET /_eql/search/FmNJRUZ1YWZCU3dHY1BIOUhaenVSRkEaaXFlZ3h4c1RTWFNocDdnY2FSaERnUTozNDE=?keep_alive=5d
  577. ----
  578. // TEST[skip: no access to search ID]
  579. You can use the <<delete-async-eql-search-api,delete async EQL search API>> to
  580. manually delete an async EQL search before the `keep_alive` period ends. If the
  581. search is still ongoing, this cancels the search request.
  582. The following request deletes an async EQL search and its results.
  583. [source,console]
  584. ----
  585. DELETE /_eql/search/FmNJRUZ1YWZCU3dHY1BIOUhaenVSRkEaaXFlZ3h4c1RTWFNocDdnY2FSaERnUTozNDE=?keep_alive=5d
  586. ----
  587. // TEST[skip: no access to search ID]
  588. [discrete]
  589. [[eql-search-store-sync-eql-search]]
  590. === Store synchronous EQL searches
  591. By default, the EQL search API only stores async searches that cannot be
  592. completed within the period set by `wait_for_completion_timeout`.
  593. To save the results of searches that complete during this period, set the
  594. `keep_on_completion` parameter to `true`.
  595. In the following search request, `keep_on_completion` is `true`. This means the
  596. search results are stored on the cluster, even if the search completes within
  597. the `2s` (two-second) period set by the `wait_for_completion_timeout` parameter.
  598. [source,console]
  599. ----
  600. GET /my-index-000001/_eql/search
  601. {
  602. "keep_on_completion": true,
  603. "wait_for_completion_timeout": "2s",
  604. "query": """
  605. process where process.name == "cmd.exe"
  606. """
  607. }
  608. ----
  609. // TEST[setup:sec_logs]
  610. The API returns the following response. A search ID is provided in the `id`
  611. property. `is_partial` and `is_running` are `false`, indicating the EQL search
  612. was synchronous and returned complete results in `hits`.
  613. [source,console-result]
  614. ----
  615. {
  616. "id": "FjlmbndxNmJjU0RPdExBTGg0elNOOEEaQk9xSjJBQzBRMldZa1VVQ2pPa01YUToxMDY=",
  617. "is_partial": false,
  618. "is_running": false,
  619. "took": 52,
  620. "timed_out": false,
  621. "hits": ...
  622. }
  623. ----
  624. // TESTRESPONSE[s/FjlmbndxNmJjU0RPdExBTGg0elNOOEEaQk9xSjJBQzBRMldZa1VVQ2pPa01YUToxMDY=/$body.id/]
  625. // TESTRESPONSE[s/"took": 52/"took": $body.took/]
  626. // TESTRESPONSE[s/"hits": \.\.\./"hits": $body.hits/]
  627. You can use the search ID and the <<get-async-eql-search-api,get async EQL
  628. search API>> to retrieve the same results later.
  629. [source,console]
  630. ----
  631. GET /_eql/search/FjlmbndxNmJjU0RPdExBTGg0elNOOEEaQk9xSjJBQzBRMldZa1VVQ2pPa01YUToxMDY=
  632. ----
  633. // TEST[skip: no access to search ID]
  634. Saved synchronous searches are still subject to the retention period set by the
  635. `keep_alive` parameter. After this period, the search and its results are
  636. deleted.
  637. You can also manually delete saved synchronous searches using the
  638. <<delete-async-eql-search-api,delete async EQL search API>>.
  639. include::syntax.asciidoc[]
  640. include::functions.asciidoc[]
  641. include::pipes.asciidoc[]
  642. include::detect-threats-with-eql.asciidoc[]