Investigation and Threat Hunting: Discover, Timeline, and Query Languages
Three query languages, three jobs
KQL is the Kibana default: field: value, quoted phrases, wildcards, ranges with >=, and explicit and/or/not. It is forgiving but does not allow a leading wildcard efficiently and needs an explicit * to test field existence. Lucene syntax is available in Discover when you switch modes; it is closer to Elasticsearch query string syntax and behaves differently for nested and analyzed fields. EQL answers relationship questions - same-process sequences, parent/child lineage, sequence by host.name - and is the language behind Timeline's correlation of events into a story. ES|QL brings piped transformations (| stats ... by ...) for aggregation-style hunting. Knowing which language can express a join or an aggregation is frequently tested.
Discover and Timeline
Discover is index-pattern driven: it queries the data view selected in the current space, so an empty result often means a wrong data view or a time range outside the event window, not a missing event. Timeline adds investigation structure: it queries one or more specified indices or data views, supports pinned and highlighted events, notes, and templates that preserve columns and query for reuse. The Analyzer and Session View build process trees and parent/child relationships, which is the fastest path from an alert on process.name to the full execution chain. Entity detail pages (host, user, network) aggregate related activity.
Traps
Do not equate "no results in Discover" with "no telemetry": check the data view, the space, the time picker, and field-level permissions. Remember that alert documents live in the per-space alerts index and are queried separately from raw events. And note that event.category values must match exactly what the integration emits before a hunt returns anything.
Worked example: hunting encoded PowerShell - query process.name : "powershell.exe" and process.args : ("-enc*" or "-encodedcommand*"), then open the results in Timeline and pivot through process.parent.* to the spawning parent.