Searching
Search answers "what is relevant to this idea?" You send a query vector — an embedding of your text — and get back the nearest entities ranked by semantic similarity. The key thing to understand up front: you compute the embedding, the API matches it. That keeps the service simple and lets you embed in the browser, in a script, or wherever you like.
Search is metered and can be turned off for cost control. Browse is always on. If a task can be addressed by id or path, prefer browsing.
The endpoint
POST https://rtxz9xxyz7.execute-api.us-east-1.amazonaws.com/search
Content-Type: application/json
Request
{
"queryVector": [0.012, -0.043, ...], // 384 floats
"topK": 10,
"indexes": ["proteins", "trials"],
"filters": {
"proteins": { "organism": "9606", "has_disease_link": true },
"trials": { "phase": "Phase 3", "overall_status": "Recruiting",
"last_update_year": 2024 }
}
}
| Field | Meaning |
|---|---|
queryVector | your text embedded to 384 floats (see below). Required. |
topK | how many results to return. |
indexes | which sets to search — "proteins", "trials", or both. |
filters | optional per-index constraints (see Filters). |
Response
{
"results": [
{ "id": "P38398", "type": "protein", "distance": 0.21, "metadata": { "...": "..." } }
],
"tookMs": 18
}
Lower distance is better — it is a distance, not a score, so the closest match
sorts first. Each result carries its id and type, so the natural next step is to
fetch nodes/<type>/<id>.json and continue by browsing.
Embedding your query
The vectors are produced by a specific model, and your query must use the same model, same settings or the distances are meaningless:
| Setting | Value |
|---|---|
| Model | Xenova/all-MiniLM-L6-v2 |
| Revision | 751bff37182d3f1213fa05d7196b954e230abad9 |
| Pooling | mean |
| Normalize | true |
| Dimension | 384 |
The site reads these from the data's embedding_config, so they stay in sync with what
the index was built with. If the config ever advertises a new model, follow it.
In the browser (Transformers.js)
import { pipeline } from '@xenova/transformers';
const embed = await pipeline(
'feature-extraction',
'Xenova/all-MiniLM-L6-v2',
{ revision: '751bff37182d3f1213fa05d7196b954e230abad9' }
);
const out = await embed('BRCA1 DNA repair and breast cancer risk',
{ pooling: 'mean', normalize: true });
const queryVector = Array.from(out.data); // 384 floats
In Python (sentence-transformers)
from sentence_transformers import SentenceTransformer
model = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2')
query_vector = model.encode(
'BRCA1 DNA repair and breast cancer risk',
normalize_embeddings=True,
).tolist() # 384 floats
all-MiniLM-L6-v2 already mean-pools, and normalize_embeddings=True matches the
normalize: true setting. The end-to-end request appears in Recipes.
Filters
Filters narrow a result set server-side, before ranking, per index:
proteins
| Filter | Example | Meaning |
|---|---|---|
organism | "9606" | NCBI taxon id (9606 = human) |
has_disease_link | true | only proteins with a disease edge |
trials
| Filter | Example | Meaning |
|---|---|---|
phase | "Phase 3" | trial phase |
overall_status | "Recruiting" | recruitment status |
last_update_year | 2024 | year of last update |
Omit filters (or any index within it) to search without constraints.
When to search vs. browse
- Search when you only have a fuzzy description — a concept, a symptom, a mechanism — and need the system to surface candidates.
- Browse when you already hold an id, a symbol, or an accession. It is exact, always available, and never silently drops a record.
A common, robust pattern is search to discover, browse to complete: one search to find entry points, then deterministic browsing to pull every connected fact without loss.