eql.asciidoc 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419
  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. With the exception of sample queries, EQL searches require that the searched
  27. data stream or index contains a _timestamp_ field. By default, EQL uses the
  28. `@timestamp` field from the {ecs-ref}[Elastic Common Schema (ECS)].
  29. EQL searches also require an _event category_ field, unless you use the
  30. <<eql-syntax-match-any-event-category,`any` keyword>> to search for documents
  31. without an event category field. By default, EQL uses the ECS `event.category`
  32. field.
  33. To use a different timestamp or event category field, see
  34. <<specify-a-timestamp-or-event-category-field>>.
  35. TIP: While no schema is required to use EQL, we recommend using the
  36. {ecs-ref}[ECS]. EQL searches are designed to work with core ECS fields by
  37. default.
  38. [discrete]
  39. [[run-an-eql-search]]
  40. === Run an EQL search
  41. Use the <<eql-search-api,EQL search API>> to run a <<eql-basic-syntax,basic EQL
  42. query>>.
  43. ////
  44. [source,console]
  45. ----
  46. DELETE /_data_stream/*
  47. DELETE /_index_template/*
  48. ----
  49. // TEARDOWN
  50. ////
  51. [source,console]
  52. ----
  53. GET /my-data-stream/_eql/search
  54. {
  55. "query": """
  56. process where process.name == "regsvr32.exe"
  57. """
  58. }
  59. ----
  60. // TEST[setup:sec_logs]
  61. By default, basic EQL queries return the 10 most recent matching events in the
  62. `hits.events` property. These hits are sorted by timestamp, converted to
  63. milliseconds since the {wikipedia}/Unix_time[Unix epoch], in ascending order.
  64. [source,console-result]
  65. ----
  66. {
  67. "is_partial": false,
  68. "is_running": false,
  69. "took": 60,
  70. "timed_out": false,
  71. "hits": {
  72. "total": {
  73. "value": 2,
  74. "relation": "eq"
  75. },
  76. "events": [
  77. {
  78. "_index": ".ds-my-data-stream-2099.12.07-000001",
  79. "_id": "OQmfCaduce8zoHT93o4H",
  80. "_source": {
  81. "@timestamp": "2099-12-07T11:07:09.000Z",
  82. "event": {
  83. "category": "process",
  84. "id": "aR3NWVOs",
  85. "sequence": 4
  86. },
  87. "process": {
  88. "pid": 2012,
  89. "name": "regsvr32.exe",
  90. "command_line": "regsvr32.exe /s /u /i:https://...RegSvr32.sct scrobj.dll",
  91. "executable": "C:\\Windows\\System32\\regsvr32.exe"
  92. }
  93. }
  94. },
  95. {
  96. "_index": ".ds-my-data-stream-2099.12.07-000001",
  97. "_id": "xLkCaj4EujzdNSxfYLbO",
  98. "_source": {
  99. "@timestamp": "2099-12-07T11:07:10.000Z",
  100. "event": {
  101. "category": "process",
  102. "id": "GTSmSqgz0U",
  103. "sequence": 6,
  104. "type": "termination"
  105. },
  106. "process": {
  107. "pid": 2012,
  108. "name": "regsvr32.exe",
  109. "executable": "C:\\Windows\\System32\\regsvr32.exe"
  110. }
  111. }
  112. }
  113. ]
  114. }
  115. }
  116. ----
  117. // TESTRESPONSE[s/"took": 60/"took": $body.took/]
  118. // TESTRESPONSE[s/"_index": ".ds-my-data-stream-2099.12.07-000001"/"_index": $body.hits.events.0._index/]
  119. // TESTRESPONSE[s/"_id": "OQmfCaduce8zoHT93o4H"/"_id": $body.hits.events.0._id/]
  120. // TESTRESPONSE[s/"_id": "xLkCaj4EujzdNSxfYLbO"/"_id": $body.hits.events.1._id/]
  121. Use the `size` parameter to get a smaller or larger set of hits:
  122. [source,console]
  123. ----
  124. GET /my-data-stream/_eql/search
  125. {
  126. "query": """
  127. process where process.name == "regsvr32.exe"
  128. """,
  129. "size": 50
  130. }
  131. ----
  132. // TEST[setup:sec_logs]
  133. [discrete]
  134. [[eql-search-sequence]]
  135. === Search for a sequence of events
  136. Use EQL's <<eql-sequences,sequence syntax>> to search for a series of
  137. ordered events. List the event items in ascending chronological order,
  138. with the most recent event listed last:
  139. [source,console]
  140. ----
  141. GET /my-data-stream/_eql/search
  142. {
  143. "query": """
  144. sequence
  145. [ process where process.name == "regsvr32.exe" ]
  146. [ file where stringContains(file.name, "scrobj.dll") ]
  147. """
  148. }
  149. ----
  150. // TEST[setup:sec_logs]
  151. The response's `hits.sequences` property contains the 10 most recent matching
  152. sequences.
  153. [source,console-result]
  154. ----
  155. {
  156. ...
  157. "hits": {
  158. "total": ...,
  159. "sequences": [
  160. {
  161. "events": [
  162. {
  163. "_index": ".ds-my-data-stream-2099.12.07-000001",
  164. "_id": "OQmfCaduce8zoHT93o4H",
  165. "_source": {
  166. "@timestamp": "2099-12-07T11:07:09.000Z",
  167. "event": {
  168. "category": "process",
  169. "id": "aR3NWVOs",
  170. "sequence": 4
  171. },
  172. "process": {
  173. "pid": 2012,
  174. "name": "regsvr32.exe",
  175. "command_line": "regsvr32.exe /s /u /i:https://...RegSvr32.sct scrobj.dll",
  176. "executable": "C:\\Windows\\System32\\regsvr32.exe"
  177. }
  178. }
  179. },
  180. {
  181. "_index": ".ds-my-data-stream-2099.12.07-000001",
  182. "_id": "yDwnGIJouOYGBzP0ZE9n",
  183. "_source": {
  184. "@timestamp": "2099-12-07T11:07:10.000Z",
  185. "event": {
  186. "category": "file",
  187. "id": "tZ1NWVOs",
  188. "sequence": 5
  189. },
  190. "process": {
  191. "pid": 2012,
  192. "name": "regsvr32.exe",
  193. "executable": "C:\\Windows\\System32\\regsvr32.exe"
  194. },
  195. "file": {
  196. "path": "C:\\Windows\\System32\\scrobj.dll",
  197. "name": "scrobj.dll"
  198. }
  199. }
  200. }
  201. ]
  202. }
  203. ]
  204. }
  205. }
  206. ----
  207. // TESTRESPONSE[s/ \.\.\.\n/"is_partial": false, "is_running": false, "took": $body.took, "timed_out": false,/]
  208. // TESTRESPONSE[s/"total": \.\.\.,/"total": { "value": 1, "relation": "eq" },/]
  209. // TESTRESPONSE[s/"_index": ".ds-my-data-stream-2099.12.07-000001"/"_index": $body.hits.sequences.0.events.0._index/]
  210. // TESTRESPONSE[s/"_id": "OQmfCaduce8zoHT93o4H"/"_id": $body.hits.sequences.0.events.0._id/]
  211. // TESTRESPONSE[s/"_id": "yDwnGIJouOYGBzP0ZE9n"/"_id": $body.hits.sequences.0.events.1._id/]
  212. Use <<eql-with-maxspan-keywords,`with maxspan`>> to constrain matching sequences
  213. to a timespan:
  214. [source,console]
  215. ----
  216. GET /my-data-stream/_eql/search
  217. {
  218. "query": """
  219. sequence with maxspan=1h
  220. [ process where process.name == "regsvr32.exe" ]
  221. [ file where stringContains(file.name, "scrobj.dll") ]
  222. """
  223. }
  224. ----
  225. // TEST[setup:sec_logs]
  226. Use the <<eql-by-keyword,`by` keyword>> to match events that share the
  227. same field values:
  228. [source,console]
  229. ----
  230. GET /my-data-stream/_eql/search
  231. {
  232. "query": """
  233. sequence with maxspan=1h
  234. [ process where process.name == "regsvr32.exe" ] by process.pid
  235. [ file where stringContains(file.name, "scrobj.dll") ] by process.pid
  236. """
  237. }
  238. ----
  239. // TEST[setup:sec_logs]
  240. If a field value should be shared across all events, use the `sequence by`
  241. keyword. The following query is equivalent to the previous one.
  242. [source,console]
  243. ----
  244. GET /my-data-stream/_eql/search
  245. {
  246. "query": """
  247. sequence by process.pid with maxspan=1h
  248. [ process where process.name == "regsvr32.exe" ]
  249. [ file where stringContains(file.name, "scrobj.dll") ]
  250. """
  251. }
  252. ----
  253. // TEST[setup:sec_logs]
  254. The `hits.sequences.join_keys` property contains the shared field values.
  255. [source,console-result]
  256. ----
  257. {
  258. ...
  259. "hits": ...,
  260. "sequences": [
  261. {
  262. "join_keys": [
  263. 2012
  264. ],
  265. "events": ...
  266. }
  267. ]
  268. }
  269. }
  270. ----
  271. // TESTRESPONSE[s/ \.\.\.\n/"is_partial": false, "is_running": false, "took": $body.took, "timed_out": false,/]
  272. // TESTRESPONSE[s/"hits": \.\.\.,/"hits": { "total": { "value": 1, "relation": "eq" },/]
  273. // TESTRESPONSE[s/"events": \.\.\./"events": $body.hits.sequences.0.events/]
  274. Use the <<eql-until-keyword,`until` keyword>> to specify an expiration
  275. event for sequences. Matching sequences must end before this event.
  276. [source,console]
  277. ----
  278. GET /my-data-stream/_eql/search
  279. {
  280. "query": """
  281. sequence by process.pid with maxspan=1h
  282. [ process where process.name == "regsvr32.exe" ]
  283. [ file where stringContains(file.name, "scrobj.dll") ]
  284. until [ process where event.type == "termination" ]
  285. """
  286. }
  287. ----
  288. // TEST[setup:sec_logs]
  289. [discrete]
  290. [[eql-search-sample]]
  291. === Sample chronologically unordered events
  292. Use EQL's <<eql-samples,sample syntax>> to search for events that match one or
  293. more join keys and a set of filters. Samples are similar to sequences, but do
  294. not return events in chronological order. In fact, sample queries can run on
  295. data without a timestamp. Sample queries can be useful to find correlations in
  296. events that don't always occur in the same sequence, or that occur across long
  297. time spans.
  298. .Click to show the sample data used in the examples below
  299. [%collapsible]
  300. ====
  301. [source,console]
  302. ----
  303. PUT /my-index-000001
  304. {
  305. "mappings": {
  306. "properties": {
  307. "ip": {
  308. "type":"ip"
  309. },
  310. "version": {
  311. "type": "version"
  312. },
  313. "missing_keyword": {
  314. "type": "keyword"
  315. },
  316. "@timestamp": {
  317. "type": "date"
  318. },
  319. "type_test": {
  320. "type": "keyword"
  321. },
  322. "@timestamp_pretty": {
  323. "type": "date",
  324. "format": "dd-MM-yyyy"
  325. },
  326. "event_type": {
  327. "type": "keyword"
  328. },
  329. "event": {
  330. "properties": {
  331. "category": {
  332. "type": "alias",
  333. "path": "event_type"
  334. }
  335. }
  336. },
  337. "host": {
  338. "type": "keyword"
  339. },
  340. "os": {
  341. "type": "keyword"
  342. },
  343. "bool": {
  344. "type": "boolean"
  345. },
  346. "uptime" : {
  347. "type" : "long"
  348. },
  349. "port" : {
  350. "type" : "long"
  351. }
  352. }
  353. }
  354. }
  355. PUT /my-index-000002
  356. {
  357. "mappings": {
  358. "properties": {
  359. "ip": {
  360. "type":"ip"
  361. },
  362. "@timestamp": {
  363. "type": "date"
  364. },
  365. "@timestamp_pretty": {
  366. "type": "date",
  367. "format": "yyyy-MM-dd"
  368. },
  369. "type_test": {
  370. "type": "keyword"
  371. },
  372. "event_type": {
  373. "type": "keyword"
  374. },
  375. "event": {
  376. "properties": {
  377. "category": {
  378. "type": "alias",
  379. "path": "event_type"
  380. }
  381. }
  382. },
  383. "host": {
  384. "type": "keyword"
  385. },
  386. "op_sys": {
  387. "type": "keyword"
  388. },
  389. "bool": {
  390. "type": "boolean"
  391. },
  392. "uptime" : {
  393. "type" : "long"
  394. },
  395. "port" : {
  396. "type" : "long"
  397. }
  398. }
  399. }
  400. }
  401. PUT /my-index-000003
  402. {
  403. "mappings": {
  404. "properties": {
  405. "host_ip": {
  406. "type":"ip"
  407. },
  408. "@timestamp": {
  409. "type": "date"
  410. },
  411. "date": {
  412. "type": "date"
  413. },
  414. "event_type": {
  415. "type": "keyword"
  416. },
  417. "event": {
  418. "properties": {
  419. "category": {
  420. "type": "alias",
  421. "path": "event_type"
  422. }
  423. }
  424. },
  425. "missing_keyword": {
  426. "type": "keyword"
  427. },
  428. "host": {
  429. "type": "keyword"
  430. },
  431. "os": {
  432. "type": "keyword"
  433. },
  434. "bool": {
  435. "type": "boolean"
  436. },
  437. "uptime" : {
  438. "type" : "long"
  439. },
  440. "port" : {
  441. "type" : "long"
  442. }
  443. }
  444. }
  445. }
  446. POST /my-index-000001/_bulk?refresh
  447. {"index":{"_id":1}}
  448. {"@timestamp":"1234567891","@timestamp_pretty":"12-12-2022","missing_keyword":"test","type_test":"abc","ip":"10.0.0.1","event_type":"alert","host":"doom","uptime":0,"port":1234,"os":"win10","version":"1.0.0","id":11}
  449. {"index":{"_id":2}}
  450. {"@timestamp":"1234567892","@timestamp_pretty":"13-12-2022","event_type":"alert","type_test":"abc","host":"CS","uptime":5,"port":1,"os":"win10","version":"1.2.0","id":12}
  451. {"index":{"_id":3}}
  452. {"@timestamp":"1234567893","@timestamp_pretty":"12-12-2022","event_type":"alert","type_test":"abc","host":"farcry","uptime":1,"port":1234,"bool":false,"os":"win10","version":"2.0.0","id":13}
  453. {"index":{"_id":4}}
  454. {"@timestamp":"1234567894","@timestamp_pretty":"13-12-2022","event_type":"alert","type_test":"abc","host":"GTA","uptime":3,"port":12,"os":"slack","version":"10.0.0","id":14}
  455. {"index":{"_id":5}}
  456. {"@timestamp":"1234567895","@timestamp_pretty":"17-12-2022","event_type":"alert","host":"sniper 3d","uptime":6,"port":1234,"os":"fedora","version":"20.1.0","id":15}
  457. {"index":{"_id":6}}
  458. {"@timestamp":"1234568896","@timestamp_pretty":"17-12-2022","event_type":"alert","host":"doom","port":65123,"bool":true,"os":"redhat","version":"20.10.0","id":16}
  459. {"index":{"_id":7}}
  460. {"@timestamp":"1234567897","@timestamp_pretty":"17-12-2022","missing_keyword":"yyy","event_type":"failure","host":"doom","uptime":15,"port":1234,"bool":true,"os":"redhat","version":"20.2.0","id":17}
  461. {"index":{"_id":8}}
  462. {"@timestamp":"1234567898","@timestamp_pretty":"12-12-2022","missing_keyword":"test","event_type":"success","host":"doom","uptime":16,"port":512,"os":"win10","version":"1.2.3","id":18}
  463. {"index":{"_id":9}}
  464. {"@timestamp":"1234567899","@timestamp_pretty":"15-12-2022","missing_keyword":"test","event_type":"success","host":"GTA","port":12,"bool":true,"os":"win10","version":"1.2.3","id":19}
  465. {"index":{"_id":10}}
  466. {"@timestamp":"1234567893","missing_keyword":null,"ip":"10.0.0.5","event_type":"alert","host":"farcry","uptime":1,"port":1234,"bool":true,"os":"win10","version":"1.2.3","id":110}
  467. POST /my-index-000002/_bulk?refresh
  468. {"index":{"_id":1}}
  469. {"@timestamp":"1234567991","type_test":"abc","ip":"10.0.0.1","event_type":"alert","host":"doom","uptime":0,"port":1234,"op_sys":"win10","id":21}
  470. {"index":{"_id":2}}
  471. {"@timestamp":"1234567992","type_test":"abc","event_type":"alert","host":"CS","uptime":5,"port":1,"op_sys":"win10","id":22}
  472. {"index":{"_id":3}}
  473. {"@timestamp":"1234567993","type_test":"abc","@timestamp_pretty":"2022-12-17","event_type":"alert","host":"farcry","uptime":1,"port":1234,"bool":false,"op_sys":"win10","id":23}
  474. {"index":{"_id":4}}
  475. {"@timestamp":"1234567994","event_type":"alert","host":"GTA","uptime":3,"port":12,"op_sys":"slack","id":24}
  476. {"index":{"_id":5}}
  477. {"@timestamp":"1234567995","event_type":"alert","host":"sniper 3d","uptime":6,"port":1234,"op_sys":"fedora","id":25}
  478. {"index":{"_id":6}}
  479. {"@timestamp":"1234568996","@timestamp_pretty":"2022-12-17","ip":"10.0.0.5","event_type":"alert","host":"doom","port":65123,"bool":true,"op_sys":"redhat","id":26}
  480. {"index":{"_id":7}}
  481. {"@timestamp":"1234567997","@timestamp_pretty":"2022-12-17","event_type":"failure","host":"doom","uptime":15,"port":1234,"bool":true,"op_sys":"redhat","id":27}
  482. {"index":{"_id":8}}
  483. {"@timestamp":"1234567998","ip":"10.0.0.1","event_type":"success","host":"doom","uptime":16,"port":512,"op_sys":"win10","id":28}
  484. {"index":{"_id":9}}
  485. {"@timestamp":"1234567999","ip":"10.0.0.1","event_type":"success","host":"GTA","port":12,"bool":false,"op_sys":"win10","id":29}
  486. POST /my-index-000003/_bulk?refresh
  487. {"index":{"_id":1}}
  488. {"@timestamp":"1334567891","host_ip":"10.0.0.1","event_type":"alert","host":"doom","uptime":0,"port":12,"os":"win10","id":31}
  489. {"index":{"_id":2}}
  490. {"@timestamp":"1334567892","event_type":"alert","host":"CS","os":"win10","id":32}
  491. {"index":{"_id":3}}
  492. {"@timestamp":"1334567893","event_type":"alert","host":"farcry","bool":true,"os":"win10","id":33}
  493. {"index":{"_id":4}}
  494. {"@timestamp":"1334567894","event_type":"alert","host":"GTA","os":"slack","bool":true,"id":34}
  495. {"index":{"_id":5}}
  496. {"@timestamp":"1234567895","event_type":"alert","host":"sniper 3d","os":"fedora","id":35}
  497. {"index":{"_id":6}}
  498. {"@timestamp":"1234578896","host_ip":"10.0.0.1","event_type":"alert","host":"doom","bool":true,"os":"redhat","id":36}
  499. {"index":{"_id":7}}
  500. {"@timestamp":"1234567897","event_type":"failure","missing_keyword":"test","host":"doom","bool":true,"os":"redhat","id":37}
  501. {"index":{"_id":8}}
  502. {"@timestamp":"1234577898","event_type":"success","host":"doom","os":"win10","id":38,"date":"1671235200000"}
  503. {"index":{"_id":9}}
  504. {"@timestamp":"1234577899","host_ip":"10.0.0.5","event_type":"success","host":"GTA","bool":true,"os":"win10","id":39}
  505. ----
  506. ====
  507. A sample query specifies at least one join key, using the <<eql-by-keyword,`by`
  508. keyword>>, and up to five filters:
  509. [source,console]
  510. ----
  511. GET /my-index*/_eql/search
  512. {
  513. "query": """
  514. sample by host
  515. [any where uptime > 0]
  516. [any where port > 100]
  517. [any where bool == true]
  518. """
  519. }
  520. ----
  521. // TEST[continued]
  522. By default, the response’s `hits.sequences` property contains up to 10 samples.
  523. Each sample has a set of `join_keys` and an array with one matching event for
  524. each of the filters. Events are returned in the order of the filters they match:
  525. [source,console-result]
  526. ----
  527. {
  528. ...
  529. "hits": {
  530. "total": {
  531. "value": 2,
  532. "relation": "eq"
  533. },
  534. "sequences": [
  535. {
  536. "join_keys": [
  537. "doom" <1>
  538. ],
  539. "events": [
  540. { <2>
  541. "_index": "my-index-000001",
  542. "_id": "7",
  543. "_source": {
  544. "@timestamp": "1234567897",
  545. "@timestamp_pretty": "17-12-2022",
  546. "missing_keyword": "yyy",
  547. "event_type": "failure",
  548. "host": "doom",
  549. "uptime": 15,
  550. "port": 1234,
  551. "bool": true,
  552. "os": "redhat",
  553. "version": "20.2.0",
  554. "id": 17
  555. }
  556. },
  557. { <3>
  558. "_index": "my-index-000001",
  559. "_id": "1",
  560. "_source": {
  561. "@timestamp": "1234567891",
  562. "@timestamp_pretty": "12-12-2022",
  563. "missing_keyword": "test",
  564. "type_test": "abc",
  565. "ip": "10.0.0.1",
  566. "event_type": "alert",
  567. "host": "doom",
  568. "uptime": 0,
  569. "port": 1234,
  570. "os": "win10",
  571. "version": "1.0.0",
  572. "id": 11
  573. }
  574. },
  575. { <4>
  576. "_index": "my-index-000001",
  577. "_id": "6",
  578. "_source": {
  579. "@timestamp": "1234568896",
  580. "@timestamp_pretty": "17-12-2022",
  581. "event_type": "alert",
  582. "host": "doom",
  583. "port": 65123,
  584. "bool": true,
  585. "os": "redhat",
  586. "version": "20.10.0",
  587. "id": 16
  588. }
  589. }
  590. ]
  591. },
  592. {
  593. "join_keys": [
  594. "farcry" <5>
  595. ],
  596. "events": [
  597. {
  598. "_index": "my-index-000001",
  599. "_id": "3",
  600. "_source": {
  601. "@timestamp": "1234567893",
  602. "@timestamp_pretty": "12-12-2022",
  603. "event_type": "alert",
  604. "type_test": "abc",
  605. "host": "farcry",
  606. "uptime": 1,
  607. "port": 1234,
  608. "bool": false,
  609. "os": "win10",
  610. "version": "2.0.0",
  611. "id": 13
  612. }
  613. },
  614. {
  615. "_index": "my-index-000001",
  616. "_id": "10",
  617. "_source": {
  618. "@timestamp": "1234567893",
  619. "missing_keyword": null,
  620. "ip": "10.0.0.5",
  621. "event_type": "alert",
  622. "host": "farcry",
  623. "uptime": 1,
  624. "port": 1234,
  625. "bool": true,
  626. "os": "win10",
  627. "version": "1.2.3",
  628. "id": 110
  629. }
  630. },
  631. {
  632. "_index": "my-index-000003",
  633. "_id": "3",
  634. "_source": {
  635. "@timestamp": "1334567893",
  636. "event_type": "alert",
  637. "host": "farcry",
  638. "bool": true,
  639. "os": "win10",
  640. "id": 33
  641. }
  642. }
  643. ]
  644. }
  645. ]
  646. }
  647. }
  648. ----
  649. // TESTRESPONSE[s/ \.\.\.\n/"is_partial": false, "is_running": false, "took": $body.took, "timed_out": false,/]
  650. <1> The events in the first sample have a value of `doom` for `host`.
  651. <2> This event matches the first filter.
  652. <3> This event matches the second filter.
  653. <4> This event matches the third filter.
  654. <5> The events in the second sample have a value of `farcry` for `host`.
  655. You can specify multiple join keys:
  656. [source,console]
  657. ----
  658. GET /my-index*/_eql/search
  659. {
  660. "query": """
  661. sample by host
  662. [any where uptime > 0] by os
  663. [any where port > 100] by op_sys
  664. [any where bool == true] by os
  665. """
  666. }
  667. ----
  668. // TEST[continued]
  669. This query will return samples where each of the events shares the same value
  670. for `os` or `op_sys`, as well as for `host`. For example:
  671. [source,console-result]
  672. ----
  673. {
  674. ...
  675. "hits": {
  676. "total": {
  677. "value": 2,
  678. "relation": "eq"
  679. },
  680. "sequences": [
  681. {
  682. "join_keys": [
  683. "doom", <1>
  684. "redhat"
  685. ],
  686. "events": [
  687. {
  688. "_index": "my-index-000001",
  689. "_id": "7",
  690. "_source": {
  691. "@timestamp": "1234567897",
  692. "@timestamp_pretty": "17-12-2022",
  693. "missing_keyword": "yyy",
  694. "event_type": "failure",
  695. "host": "doom",
  696. "uptime": 15,
  697. "port": 1234,
  698. "bool": true,
  699. "os": "redhat",
  700. "version": "20.2.0",
  701. "id": 17
  702. }
  703. },
  704. {
  705. "_index": "my-index-000002",
  706. "_id": "6",
  707. "_source": {
  708. "@timestamp": "1234568996",
  709. "@timestamp_pretty": "2022-12-17",
  710. "ip": "10.0.0.5",
  711. "event_type": "alert",
  712. "host": "doom",
  713. "port": 65123,
  714. "bool": true,
  715. "op_sys": "redhat",
  716. "id": 26
  717. }
  718. },
  719. {
  720. "_index": "my-index-000001",
  721. "_id": "6",
  722. "_source": {
  723. "@timestamp": "1234568896",
  724. "@timestamp_pretty": "17-12-2022",
  725. "event_type": "alert",
  726. "host": "doom",
  727. "port": 65123,
  728. "bool": true,
  729. "os": "redhat",
  730. "version": "20.10.0",
  731. "id": 16
  732. }
  733. }
  734. ]
  735. },
  736. {
  737. "join_keys": [
  738. "farcry",
  739. "win10"
  740. ],
  741. "events": [
  742. {
  743. "_index": "my-index-000001",
  744. "_id": "3",
  745. "_source": {
  746. "@timestamp": "1234567893",
  747. "@timestamp_pretty": "12-12-2022",
  748. "event_type": "alert",
  749. "type_test": "abc",
  750. "host": "farcry",
  751. "uptime": 1,
  752. "port": 1234,
  753. "bool": false,
  754. "os": "win10",
  755. "version": "2.0.0",
  756. "id": 13
  757. }
  758. },
  759. {
  760. "_index": "my-index-000002",
  761. "_id": "3",
  762. "_source": {
  763. "@timestamp": "1234567993",
  764. "type_test": "abc",
  765. "@timestamp_pretty": "2022-12-17",
  766. "event_type": "alert",
  767. "host": "farcry",
  768. "uptime": 1,
  769. "port": 1234,
  770. "bool": false,
  771. "op_sys": "win10",
  772. "id": 23
  773. }
  774. },
  775. {
  776. "_index": "my-index-000001",
  777. "_id": "10",
  778. "_source": {
  779. "@timestamp": "1234567893",
  780. "missing_keyword": null,
  781. "ip": "10.0.0.5",
  782. "event_type": "alert",
  783. "host": "farcry",
  784. "uptime": 1,
  785. "port": 1234,
  786. "bool": true,
  787. "os": "win10",
  788. "version": "1.2.3",
  789. "id": 110
  790. }
  791. }
  792. ]
  793. }
  794. ]
  795. }
  796. }
  797. ----
  798. // TESTRESPONSE[s/ \.\.\.\n/"is_partial": false, "is_running": false, "took": $body.took, "timed_out": false,/]
  799. <1> The events in this sample have a value of `doom` for `host` and a value of
  800. `redhat` for `os` or `op_sys`.
  801. By default, the response of a sample query contains up to 10 samples, with one
  802. sample per unique set of join keys. Use the `size` parameter to get a smaller or
  803. larger set of samples. To retrieve more than one sample per set of join keys,
  804. use the `max_samples_per_key` parameter. Pipes are not supported for sample
  805. queries.
  806. [source,console]
  807. ----
  808. GET /my-index*/_eql/search
  809. {
  810. "max_samples_per_key": 2, <1>
  811. "size": 20, <2>
  812. "query": """
  813. sample
  814. [any where uptime > 0] by host,os
  815. [any where port > 100] by host,op_sys
  816. [any where bool == true] by host,os
  817. """
  818. }
  819. ----
  820. // TEST[continued]
  821. <1> Retrieve up to 2 samples per set of join keys.
  822. <2> Retrieve up to 20 samples in total.
  823. [discrete]
  824. [[retrieve-selected-fields]]
  825. === Retrieve selected fields
  826. By default, each hit in the search response includes the document `_source`,
  827. which is the entire JSON object that was provided when indexing the document.
  828. You can use the <<common-options-response-filtering,`filter_path`>> query
  829. parameter to filter the API response. For example, the following search returns
  830. only the timestamp and PID from the `_source` of each matching event.
  831. [source,console]
  832. ----
  833. GET /my-data-stream/_eql/search?filter_path=hits.events._source.@timestamp,hits.events._source.process.pid
  834. {
  835. "query": """
  836. process where process.name == "regsvr32.exe"
  837. """
  838. }
  839. ----
  840. // TEST[setup:sec_logs]
  841. The API returns the following response.
  842. [source,console-result]
  843. ----
  844. {
  845. "hits": {
  846. "events": [
  847. {
  848. "_source": {
  849. "@timestamp": "2099-12-07T11:07:09.000Z",
  850. "process": {
  851. "pid": 2012
  852. }
  853. }
  854. },
  855. {
  856. "_source": {
  857. "@timestamp": "2099-12-07T11:07:10.000Z",
  858. "process": {
  859. "pid": 2012
  860. }
  861. }
  862. }
  863. ]
  864. }
  865. }
  866. ----
  867. You can also use the `fields` parameter to retrieve and format specific fields
  868. in the response. This field is identical to the search API's
  869. <<search-fields,`fields` parameter>>.
  870. include::{es-repo-dir}/search/search-your-data/retrieve-selected-fields.asciidoc[tag=fields-param-desc]
  871. The following search request uses the `fields` parameter to retrieve values for
  872. the `event.type` field, all fields starting with `process.`, and the
  873. `@timestamp` field. The request also uses the `filter_path` query parameter to
  874. exclude the `_source` of each hit.
  875. [source,console]
  876. ----
  877. GET /my-data-stream/_eql/search?filter_path=-hits.events._source
  878. {
  879. "query": """
  880. process where process.name == "regsvr32.exe"
  881. """,
  882. "fields": [
  883. "event.type",
  884. "process.*", <1>
  885. {
  886. "field": "@timestamp",
  887. "format": "epoch_millis" <2>
  888. }
  889. ]
  890. }
  891. ----
  892. // TEST[setup:sec_logs]
  893. include::{es-repo-dir}/search/search-your-data/retrieve-selected-fields.asciidoc[tag=fields-param-callouts]
  894. The response includes values as a flat list in the `fields` section for each
  895. hit.
  896. [source,console-result]
  897. ----
  898. {
  899. ...
  900. "hits": {
  901. "total": ...,
  902. "events": [
  903. {
  904. "_index": ".ds-my-data-stream-2099.12.07-000001",
  905. "_id": "OQmfCaduce8zoHT93o4H",
  906. "fields": {
  907. "process.name": [
  908. "regsvr32.exe"
  909. ],
  910. "process.name.keyword": [
  911. "regsvr32.exe"
  912. ],
  913. "@timestamp": [
  914. "4100324829000"
  915. ],
  916. "process.command_line": [
  917. "regsvr32.exe /s /u /i:https://...RegSvr32.sct scrobj.dll"
  918. ],
  919. "process.command_line.keyword": [
  920. "regsvr32.exe /s /u /i:https://...RegSvr32.sct scrobj.dll"
  921. ],
  922. "process.executable.keyword": [
  923. "C:\\Windows\\System32\\regsvr32.exe"
  924. ],
  925. "process.pid": [
  926. 2012
  927. ],
  928. "process.executable": [
  929. "C:\\Windows\\System32\\regsvr32.exe"
  930. ]
  931. }
  932. },
  933. ....
  934. ]
  935. }
  936. }
  937. ----
  938. // TESTRESPONSE[s/ \.\.\.\n/"is_partial": false, "is_running": false, "took": $body.took, "timed_out": false,/]
  939. // TESTRESPONSE[s/"total": \.\.\.,/"total": { "value": 2, "relation": "eq" },/]
  940. // TESTRESPONSE[s/"_index": ".ds-my-data-stream-2099.12.07-000001"/"_index": $body.hits.events.0._index/]
  941. // TESTRESPONSE[s/"_id": "OQmfCaduce8zoHT93o4H"/"_id": $body.hits.events.0._id/]
  942. // TESTRESPONSE[s/ \.\.\.\.\n/$body.hits.events.1/]
  943. [discrete]
  944. [[eql-use-runtime-fields]]
  945. === Use runtime fields
  946. Use the `runtime_mappings` parameter to extract and create <<runtime,runtime
  947. fields>> during a search. Use the `fields` parameter to include runtime fields
  948. in the response.
  949. The following search creates a `day_of_week` runtime field from the `@timestamp`
  950. and returns it in the response.
  951. [source,console]
  952. ----
  953. GET /my-data-stream/_eql/search?filter_path=-hits.events._source
  954. {
  955. "runtime_mappings": {
  956. "day_of_week": {
  957. "type": "keyword",
  958. "script": "emit(doc['@timestamp'].value.dayOfWeekEnum.toString())"
  959. }
  960. },
  961. "query": """
  962. process where process.name == "regsvr32.exe"
  963. """,
  964. "fields": [
  965. "@timestamp",
  966. "day_of_week"
  967. ]
  968. }
  969. ----
  970. // TEST[setup:sec_logs]
  971. The API returns:
  972. [source,console-result]
  973. ----
  974. {
  975. ...
  976. "hits": {
  977. "total": ...,
  978. "events": [
  979. {
  980. "_index": ".ds-my-data-stream-2099.12.07-000001",
  981. "_id": "OQmfCaduce8zoHT93o4H",
  982. "fields": {
  983. "@timestamp": [
  984. "2099-12-07T11:07:09.000Z"
  985. ],
  986. "day_of_week": [
  987. "MONDAY"
  988. ]
  989. }
  990. },
  991. ....
  992. ]
  993. }
  994. }
  995. ----
  996. // TESTRESPONSE[s/ \.\.\.\n/"is_partial": false, "is_running": false, "took": $body.took, "timed_out": false,/]
  997. // TESTRESPONSE[s/"total": \.\.\.,/"total": { "value": 2, "relation": "eq" },/]
  998. // TESTRESPONSE[s/"_index": ".ds-my-data-stream-2099.12.07-000001"/"_index": $body.hits.events.0._index/]
  999. // TESTRESPONSE[s/"_id": "OQmfCaduce8zoHT93o4H"/"_id": $body.hits.events.0._id/]
  1000. // TESTRESPONSE[s/ \.\.\.\.\n/$body.hits.events.1/]
  1001. [discrete]
  1002. [[specify-a-timestamp-or-event-category-field]]
  1003. === Specify a timestamp or event category field
  1004. The EQL search API uses the `@timestamp` and `event.category` fields from the
  1005. {ecs-ref}[ECS] by default. To specify different fields, use the
  1006. `timestamp_field` and `event_category_field` parameters:
  1007. [source,console]
  1008. ----
  1009. GET /my-data-stream/_eql/search
  1010. {
  1011. "timestamp_field": "file.accessed",
  1012. "event_category_field": "file.type",
  1013. "query": """
  1014. file where (file.size > 1 and file.type == "file")
  1015. """
  1016. }
  1017. ----
  1018. // TEST[setup:sec_logs]
  1019. The event category field must be mapped as a <<keyword,`keyword`>> family field
  1020. type. The timestamp field should be mapped as a <<date,`date`>> field type.
  1021. <<date_nanos,`date_nanos`>> timestamp fields are not supported. You cannot use a
  1022. <<nested,`nested`>> field or the sub-fields of a `nested` field as the timestamp
  1023. or event category field.
  1024. [discrete]
  1025. [[eql-search-specify-a-sort-tiebreaker]]
  1026. === Specify a sort tiebreaker
  1027. By default, the EQL search API returns matching hits by timestamp. If two or
  1028. more events share the same timestamp, {es} uses a tiebreaker field value to sort
  1029. the events in ascending order. {es} orders events with no
  1030. tiebreaker value after events with a value.
  1031. If you don't specify a tiebreaker field or the events also share the same
  1032. tiebreaker value, {es} considers the events concurrent and may
  1033. not return them in a consistent sort order.
  1034. To specify a tiebreaker field, use the `tiebreaker_field` parameter. If you use
  1035. the {ecs-ref}[ECS], we recommend using `event.sequence` as the tiebreaker field.
  1036. [source,console]
  1037. ----
  1038. GET /my-data-stream/_eql/search
  1039. {
  1040. "tiebreaker_field": "event.sequence",
  1041. "query": """
  1042. process where process.name == "cmd.exe" and stringContains(process.executable, "System32")
  1043. """
  1044. }
  1045. ----
  1046. // TEST[setup:sec_logs]
  1047. [discrete]
  1048. [[eql-search-filter-query-dsl]]
  1049. === Filter using Query DSL
  1050. The `filter` parameter uses <<query-dsl,Query DSL>> to limit the documents on
  1051. which an EQL query runs.
  1052. [source,console]
  1053. ----
  1054. GET /my-data-stream/_eql/search
  1055. {
  1056. "filter": {
  1057. "range": {
  1058. "@timestamp": {
  1059. "gte": "now-1d/d",
  1060. "lt": "now/d"
  1061. }
  1062. }
  1063. },
  1064. "query": """
  1065. file where (file.type == "file" and file.name == "cmd.exe")
  1066. """
  1067. }
  1068. ----
  1069. // TEST[setup:sec_logs]
  1070. [discrete]
  1071. [[eql-search-async]]
  1072. === Run an async EQL search
  1073. By default, EQL search requests are synchronous and wait for complete results
  1074. before returning a response. However, complete results can take longer for
  1075. searches across large data sets or <<data-tiers,frozen>> data.
  1076. To avoid long waits, run an async EQL search. Set `wait_for_completion_timeout`
  1077. to a duration you'd like to wait for synchronous results.
  1078. [source,console]
  1079. ----
  1080. GET /my-data-stream/_eql/search
  1081. {
  1082. "wait_for_completion_timeout": "2s",
  1083. "query": """
  1084. process where process.name == "cmd.exe"
  1085. """
  1086. }
  1087. ----
  1088. // TEST[setup:sec_logs]
  1089. If the request doesn't finish within the timeout period, the search becomes async
  1090. and returns a response that includes:
  1091. * A search ID
  1092. * An `is_partial` value of `true`, indicating the search results are
  1093. incomplete
  1094. * An `is_running` value of `true`, indicating the search is ongoing
  1095. The async search continues to run in the background without blocking other
  1096. requests.
  1097. [source,console-result]
  1098. ----
  1099. {
  1100. "id": "FmNJRUZ1YWZCU3dHY1BIOUhaenVSRkEaaXFlZ3h4c1RTWFNocDdnY2FSaERnUTozNDE=",
  1101. "is_partial": true,
  1102. "is_running": true,
  1103. "took": 2000,
  1104. "timed_out": false,
  1105. "hits": ...
  1106. }
  1107. ----
  1108. // TESTRESPONSE[s/FmNJRUZ1YWZCU3dHY1BIOUhaenVSRkEaaXFlZ3h4c1RTWFNocDdnY2FSaERnUTozNDE=/$body.id/]
  1109. // TESTRESPONSE[s/"is_partial": true/"is_partial": $body.is_partial/]
  1110. // TESTRESPONSE[s/"is_running": true/"is_running": $body.is_running/]
  1111. // TESTRESPONSE[s/"took": 2000/"took": $body.took/]
  1112. // TESTRESPONSE[s/"hits": \.\.\./"hits": $body.hits/]
  1113. To check the progress of an async search, use the <<get-async-eql-search-api,get
  1114. async EQL search API>> with the search ID. Specify how long you'd like for
  1115. complete results in the `wait_for_completion_timeout` parameter.
  1116. [source,console]
  1117. ----
  1118. GET /_eql/search/FmNJRUZ1YWZCU3dHY1BIOUhaenVSRkEaaXFlZ3h4c1RTWFNocDdnY2FSaERnUTozNDE=?wait_for_completion_timeout=2s
  1119. ----
  1120. // TEST[skip: no access to search ID]
  1121. If the response's `is_running` value is `false`, the async search has finished.
  1122. If the `is_partial` value is `false`, the returned search results are
  1123. complete.
  1124. [source,console-result]
  1125. ----
  1126. {
  1127. "id": "FmNJRUZ1YWZCU3dHY1BIOUhaenVSRkEaaXFlZ3h4c1RTWFNocDdnY2FSaERnUTozNDE=",
  1128. "is_partial": false,
  1129. "is_running": false,
  1130. "took": 2000,
  1131. "timed_out": false,
  1132. "hits": ...
  1133. }
  1134. ----
  1135. // TESTRESPONSE[s/FmNJRUZ1YWZCU3dHY1BIOUhaenVSRkEaaXFlZ3h4c1RTWFNocDdnY2FSaERnUTozNDE=/$body.id/]
  1136. // TESTRESPONSE[s/"took": 2000/"took": $body.took/]
  1137. // TESTRESPONSE[s/"hits": \.\.\./"hits": $body.hits/]
  1138. Another more lightweight way to check the progress of an async search is to use
  1139. the <<get-async-eql-status-api,get async EQL status API>> with the search ID.
  1140. [source,console]
  1141. ----
  1142. GET /_eql/search/status/FmNJRUZ1YWZCU3dHY1BIOUhaenVSRkEaaXFlZ3h4c1RTWFNocDdnY2FSaERnUTozNDE=
  1143. ----
  1144. // TEST[skip: no access to search ID]
  1145. [source,console-result]
  1146. ----
  1147. {
  1148. "id": "FmNJRUZ1YWZCU3dHY1BIOUhaenVSRkEaaXFlZ3h4c1RTWFNocDdnY2FSaERnUTozNDE=",
  1149. "is_running": false,
  1150. "is_partial": false,
  1151. "expiration_time_in_millis": 1611690295000,
  1152. "completion_status": 200
  1153. }
  1154. ----
  1155. // TESTRESPONSE[s/FmNJRUZ1YWZCU3dHY1BIOUhaenVSRkEaaXFlZ3h4c1RTWFNocDdnY2FSaERnUTozNDE=/$body.id/]
  1156. // TESTRESPONSE[s/"expiration_time_in_millis": 1611690295000/"expiration_time_in_millis": $body.expiration_time_in_millis/]
  1157. [discrete]
  1158. [[eql-search-store-async-eql-search]]
  1159. === Change the search retention period
  1160. By default, the EQL search API stores async searches for five days. After this
  1161. period, any searches and their results are deleted. Use the `keep_alive`
  1162. parameter to change this retention period:
  1163. [source,console]
  1164. ----
  1165. GET /my-data-stream/_eql/search
  1166. {
  1167. "keep_alive": "2d",
  1168. "wait_for_completion_timeout": "2s",
  1169. "query": """
  1170. process where process.name == "cmd.exe"
  1171. """
  1172. }
  1173. ----
  1174. // TEST[setup:sec_logs]
  1175. You can use the <<get-async-eql-search-api,get async EQL search API>>'s
  1176. `keep_alive` parameter to later change the retention period. The new retention
  1177. period starts after the get request runs.
  1178. [source,console]
  1179. ----
  1180. GET /_eql/search/FmNJRUZ1YWZCU3dHY1BIOUhaenVSRkEaaXFlZ3h4c1RTWFNocDdnY2FSaERnUTozNDE=?keep_alive=5d
  1181. ----
  1182. // TEST[skip: no access to search ID]
  1183. Use the <<delete-async-eql-search-api,delete async EQL search API>> to
  1184. manually delete an async EQL search before the `keep_alive` period ends. If the
  1185. search is still ongoing, {es} cancels the search request.
  1186. [source,console]
  1187. ----
  1188. DELETE /_eql/search/FmNJRUZ1YWZCU3dHY1BIOUhaenVSRkEaaXFlZ3h4c1RTWFNocDdnY2FSaERnUTozNDE=
  1189. ----
  1190. // TEST[skip: no access to search ID]
  1191. [discrete]
  1192. [[eql-search-store-sync-eql-search]]
  1193. === Store synchronous EQL searches
  1194. By default, the EQL search API only stores async searches. To save a synchronous
  1195. search, set `keep_on_completion` to `true`:
  1196. [source,console]
  1197. ----
  1198. GET /my-data-stream/_eql/search
  1199. {
  1200. "keep_on_completion": true,
  1201. "wait_for_completion_timeout": "2s",
  1202. "query": """
  1203. process where process.name == "cmd.exe"
  1204. """
  1205. }
  1206. ----
  1207. // TEST[setup:sec_logs]
  1208. The response includes a search ID. `is_partial` and `is_running` are `false`,
  1209. indicating the EQL search was synchronous and returned complete results.
  1210. [source,console-result]
  1211. ----
  1212. {
  1213. "id": "FjlmbndxNmJjU0RPdExBTGg0elNOOEEaQk9xSjJBQzBRMldZa1VVQ2pPa01YUToxMDY=",
  1214. "is_partial": false,
  1215. "is_running": false,
  1216. "took": 52,
  1217. "timed_out": false,
  1218. "hits": ...
  1219. }
  1220. ----
  1221. // TESTRESPONSE[s/FjlmbndxNmJjU0RPdExBTGg0elNOOEEaQk9xSjJBQzBRMldZa1VVQ2pPa01YUToxMDY=/$body.id/]
  1222. // TESTRESPONSE[s/"took": 52/"took": $body.took/]
  1223. // TESTRESPONSE[s/"hits": \.\.\./"hits": $body.hits/]
  1224. Use the <<get-async-eql-search-api,get async EQL search API>> to get the
  1225. same results later:
  1226. [source,console]
  1227. ----
  1228. GET /_eql/search/FjlmbndxNmJjU0RPdExBTGg0elNOOEEaQk9xSjJBQzBRMldZa1VVQ2pPa01YUToxMDY=
  1229. ----
  1230. // TEST[skip: no access to search ID]
  1231. Saved synchronous searches are still subject to the `keep_alive` parameter's
  1232. retention period. When this period ends, the search and its results are deleted.
  1233. You can also check only the status of the saved synchronous search without
  1234. results by using <<get-async-eql-status-api,get async EQL status API>>.
  1235. You can also manually delete saved synchronous searches using the
  1236. <<delete-async-eql-search-api,delete async EQL search API>>.
  1237. [discrete]
  1238. [[run-eql-search-across-clusters]]
  1239. === Run an EQL search across clusters
  1240. experimental::[]
  1241. The EQL search API supports <<modules-cross-cluster-search,cross-cluster search>>.
  1242. However, the local and <<remote-clusters,remote clusters>>
  1243. must use the same {es} version
  1244. if they have versions prior to 7.17.7 (included) or prior to 8.5.1 (included).
  1245. The following <<cluster-update-settings,cluster update settings>> request
  1246. adds two remote clusters: `cluster_one` and `cluster_two`.
  1247. [source,console]
  1248. ----
  1249. PUT /_cluster/settings
  1250. {
  1251. "persistent": {
  1252. "cluster": {
  1253. "remote": {
  1254. "cluster_one": {
  1255. "seeds": [
  1256. "127.0.0.1:9300"
  1257. ]
  1258. },
  1259. "cluster_two": {
  1260. "seeds": [
  1261. "127.0.0.1:9301"
  1262. ]
  1263. }
  1264. }
  1265. }
  1266. }
  1267. }
  1268. ----
  1269. // TEST[setup:host]
  1270. // TEST[s/127.0.0.1:930\d+/\${transport_host}/]
  1271. To target a data stream or index on a remote cluster, use the
  1272. `<cluster>:<target>` syntax.
  1273. [source,console]
  1274. ----
  1275. GET /cluster_one:my-data-stream,cluster_two:my-data-stream/_eql/search
  1276. {
  1277. "query": """
  1278. process where process.name == "regsvr32.exe"
  1279. """
  1280. }
  1281. ----
  1282. // TEST[continued]
  1283. // TEST[setup:sec_logs]
  1284. // TEST[teardown:data_stream_cleanup]
  1285. [discrete]
  1286. [[eql-circuit-breaker]]
  1287. === EQL circuit breaker settings
  1288. The relevant circuit breaker settings can be found in the <<circuit-breakers-page-eql, Circuit Breakers page>>.
  1289. include::syntax.asciidoc[]
  1290. include::functions.asciidoc[]
  1291. include::pipes.asciidoc[]
  1292. include::detect-threats-with-eql.asciidoc[]