Skip to content

Work with search results

What this covers

Choose event fields, interpret result pages, and handle asynchronous searches in an integration. This guide builds on the Search quickstart.

Prerequisites

Complete the quickstart with your tenant credentials. Keep the returned search URN for status checks and result reads.

Workflow

Choose event fields

Use QL's | fields clause to select event fields when you create a search:

from process where earliest = -1h | fields sensor_type, commandline, image_path

In a live test, an unprojected search returned 861 field definitions. The projection returned eight, including automatic and enriched fields. The selected event fields do not determine every response field.

QL projection controls event fields. The GraphQL selection set controls response sections such as fields, totals, and nextCursor. values is a JSON scalar, so you cannot select its individual fields in GraphQL.

Select only the response sections your client needs. Use limit to bound rows per page. Projection reduces response content, but does not establish lower scan cost or faster execution.

Preserve inputs for enriched fields

The API derives some response fields from event data. Two important examples are hostname and enrichSummary. Their presence in result metadata does not make them valid projection inputs.

The API rejects both names in | fields. Select their underlying event fields instead. For hostname enrichment, retain host_id:

from process where earliest = -1h | fields host_id, commandline, image_path

Without host_id, the tested rows omitted hostname. Retaining it produced a populated hostname in both sampled rows. A host ID does not guarantee that the API can resolve a hostname.

enrichSummary uses inputs that depend on the event. Removing those inputs can reduce the summary's content. Check representative results before you narrow a projection that relies on enrichment.

Interpret a result page

values contains an array of JSON row objects. fields describes available fields, including names and types. A metadata entry does not guarantee a populated value in every row.

Handle null and absent values. Values can include nested objects and lists.

Metadata uses dotted names for nested fields, such as process_file_hash.md5.

Use baseType to interpret values, including timestamp units and list or map shapes. See the BaseType enum for its values.

When available, totals.total counts the result set, and totals.subtotals groups counts by schema. Neither count is the length of the current page's values array.

Track one execution

A search can create multiple partitions, each with a job for an output schema. Use the search URN to read the combined results. Use a partition URN only when you need that partition's status or results.

Keep each cursor with the search URN that produced it. Pass nextCursor unchanged as cursor in the next results request. Do not construct or interpret cursor contents.

Error handling

Check requests and execution separately

Check all three layers before you treat a response as successful:

Layer What to check What to do
HTTP Status and response body Handle authentication, throttling, and server failures.
GraphQL Top-level errors, including on HTTP 200 Inspect the errors before using returned data.
Search execution status, outcome.success, and diagnostics Wait for completion, then decide whether the results meet your needs.

UNKNOWN is normal before completion. Once status is COMPLETE, ALL means every partition succeeded. PARTIAL means some succeeded, and NONE means none succeeded.

Choose whether your integration accepts partial results. Inspect outcome.errors for partition messages. Search and partition errors can also contain warnings, including on successful execution.

Use this selection when you need those diagnostics and the results' expiry:

query SearchDiagnostics($urn: URN!) {
  search(urn: $urn) {
    urn
    status
    errors
    expireTime
    outcome { success errors { urn errors } }
    searchPartitions { urn schemaType status errors }
  }
}

Bound polling and retries

Start with a client policy such as polling every five seconds. Set an overall deadline that suits your workload. These are client choices, not service limits.

A completed search can still need time to return a result page. Set a timeout for each request as well as the overall workflow. A read timeout does not mean the search failed.

Retry transient read failures with bounded backoff. Keep the same search URN and cursor when retrying a page.

Handle an uncertain creation

A createSearch timeout can leave a running search whose response you did not receive. Repeating that mutation can create another execution.

For workflows that can reuse a search, consider getOrCreateSearch. It can return a matching search that is running or complete. It compares queries by their canonical form, rather than their literal text.

Use createSearch when you need a new execution. Do not treat reuse as a guarantee of fresh results or describe it as a new run.

Constraints and considerations

Read results before expiry

search.expireTime identifies when the search's results become invalid or are discarded. Retrieve the pages you need before that time. Keeping a URN or cursor does not extend result availability.

Store retrieved data in your own system if you need it later. Do not assume a fixed retention duration from one captured search.

Check the supported surface

Use the Search reference for supported operations and fields. Additional fields exposed by introspection can remain outside the supported API.