Skip to main content
This page is an operator-first reference for building queries against Search Profiles and Search Companies. If you’re looking for full end-to-end scenarios instead, see Search endpoint examples.
Every JSON block below is copy-pasteable into the API Query Tester. If you’re not sure which operator you need, start with the decision table.

Choosing the right operator

Text vs. keyword: why “General Manager” is tricky

Most string fields in the Swarm index are mapped as both text (analyzed — lowercased, tokenized into words) and keyword under a .raw subfield (stored verbatim). Which one you query changes what “match” means.
Many fields in the mappings are aliases (e.g. current_titlejob_title, current_company_namejob_company_name). Aliases work for match, but for term/terms you should target the underlying field’s .raw — for example profile_info.job_title.raw, not profile_info.current_title.raw.
Take profile_info.job_title (aliased as current_title) and the value "General Manager":
  • match — full-text search on the analyzed field. Matches any profile whose title contains the words general or manager (default OR). “Assistant General Manager”, “General Counsel”, and “Product Manager” all match.
  • match_phrase — full-text with word order preserved. Matches titles containing the words general then manager adjacent to each other. “Senior General Manager” and “General Manager, EMEA” both match; “Manager of General Affairs” does not.
  • term on .raw — exact keyword match. Only titles that are literally "General Manager" match. Case-sensitive against the stored value.

match — any of the words

match with operator AND — all of the words, any order

match_phrase — exact phrase, adjacent, in order

term on .raw — strict exact match

term on a text field almost always returns zero results. Always target the .raw subfield for exact matches.

AND vs. OR inside one field

All words required

Use match with "operator": "AND" when every token in the query must appear in the field.

At least N of the words

minimum_should_match lets you require a fraction of the tokens instead of all-or-nothing.

AND vs. OR across multiple fields

Use bool to combine clauses. The four clause types:
  • must — AND. Contributes to score.
  • filter — AND. Does not contribute to score; faster and cacheable.
  • should — OR. If used alongside must, it only boosts score; on its own it acts as OR (at least one must match).
  • must_not — NOT.

AND across fields (data scientists in the US)

OR across fields (Google or Meta, current employees)

Because bool with only should requires at least one to match, this behaves like OR.
For a list of exact values, terms is shorter than multiple should clauses:

filter vs. must

must and filter both combine clauses with AND. The difference is scoring: must clauses contribute to a relevance score, filter clauses don’t (and are faster + cacheable). Rule of thumb: put the clauses that decide relevance in must, and the clauses that just narrow the set (locations, dates, seniorities, exists checks) in filter. Same query, two shapes — take the earlier “data scientists in the US” example. The location doesn’t need scoring, so moving it into filter is more efficient:
Both queries return the same profiles; the second is faster because the location clause is not scored.
job_title_role and job_seniorities accept a fixed set of lowercase values — see Canonical values. job_company_industry is free-form (e.g. "Software Development", "Computer Software"); values vary by source, so term matches can miss unless you know the exact string.

Negation and existence

Exclude a value (must_not)

Product managers not currently at Google:

Field must be present (exists)

Profiles with at least one email on file:

Ranges and dates

range supports gte, gt, lte, lt. Dates accept either YYYY-MM-DD or relative expressions like now-30d, now-1y, now. Profiles whose current job was updated in the last year:
Combine a range with a text search — profiles that changed to a “Head of” role in the last 90 days:
When you combine a range with a specific canonical value (like job_seniorities: "director"), the intersection can be small or empty depending on your team’s network. If a compound query returns zero, test each clause on its own first to isolate which one is over-filtering.
multi_match runs the same query text across several fields at once.

Nested fields (work experience)

Anything under profile_info.experience.* is a nested document — you can’t match it with a flat clause. Wrap the query in nested with the correct path.

Anyone who has ever worked at Google

Held a “Product Manager” role at Google in the past (not necessarily current)

For a more complete “worked there but not currently” pattern, see Search endpoint examples.

Common pitfalls

  • term on a text field returns nothing. Use .raw on the underlying field (e.g. job_title.raw, job_company_name.raw) for exact matches. Aliased names like current_title.raw do not resolve — always target the real field.
  • Keyword fields with a lowercase normalizer. Fields like job_seniorities, job_title_role, and job_company_industry are stored lowercased, so term values must be lowercase (e.g. "senior", "marketing & product management").
  • Free-form vs. canonical values. job_seniorities and job_title_role accept a fixed set of values (Canonical values); job_company_industry is enrichment-source data with varying strings — match on the text form is safer than term unless you know the exact value.
  • match_phrase is not case-sensitive. The analyzer lowercases both the query and the indexed value. If you need case-sensitivity, use term on .raw.
  • Forgetting nested. Any field path starting with profile_info.experience., profile_info.education., or profile_info.certifications. needs a nested wrapper with the matching path.
  • should without minimum_should_match when mixed with must. Once you add a must clause, should clauses only boost scoring — they no longer require any match. Set "minimum_should_match": 1 when you want OR behavior.
  • Using must for non-scored filters. Move seniorities, industries, date ranges, and exists checks into filter for a faster query.

Next steps