Three ways to search: the dedicated search() (BM25, faceted, highlighted), the hybrid SQL operator, and the typed namespace handle.

POST /search — BM25 with facets & highlights

res = client.search(
    "alice chen", "Person",
    limit=10,
    facets=["company", "risk"],
    highlight=True,
    filters={"company": "Acme Corp"},
    matching_strategy="all",
)
for hit in res.hits:
    print(hit.score, hit.fields["name"])
# 8.42 Alice Chen
{
  "hits": [{"score": 8.42, "fields": {"name": "Alice Chen", ...}}],
  "total": 1,
  "estimated_total_hits": 1,
  "facets": {"company": {"Acme Corp": 1}, "risk": {"HIGH": 1}},
  "processing_time_ms": 2.1
}

HYBRID_SEARCH — fused BM25 + vector (via SQL)

client.query(
    "HYBRID_SEARCH FROM CaseDoc "
    "QUERY 'embezzlement offshore transfers' LIMIT 3"
)
{"rows": 3, "data": [
  {"title": "Whistleblower Complaint by Carla Nunez", "_score": 12.84},
  {"title": "Acme Corp CFO Under Scrutiny",           "_score": 9.21},
  {"title": "Suspicious Activity Report",             "_score": 7.55}
]}

All three documents found, ranked by relevance — no Elasticsearch, no external service.

Weighted fusion — [graph, bm25, vector]

# Pure BM25 (keyword precision, no semantic fuzziness):
client.query(
    "HYBRID_SEARCH FROM CaseDoc QUERY 'ShellCo shell company' "
    "LIMIT 3 WEIGHTS 0.0 1.0 0.0"
)
 
# Balanced BM25 + vector via the search() door (set metric or weights to
# trigger the hybrid channel — #2672):
client.search(
    "embezzlement offshore", "CaseDoc",
    metric="cosine", weights=[0.0, 0.5, 0.5],
)

The WEIGHTS triple is [graph, bm25, vector]. Setting any one to 1.0 and the others to 0.0 gives you single-channel mode.


Next: Identity Resolution — query the IdentityIndex that SmartIngest built during ingest.