> ## Documentation Index
> Fetch the complete documentation index at: https://docs.omophub.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Python SDK - Searching OMOP medical concepts

> Search OMOP medical concepts across SNOMED, ICD-10, LOINC, and RxNorm from the OMOPHub Python SDK with keyword, semantic, and filtered queries.

## Basic Search

Search for concepts by text:

```python theme={null}
results = client.search.basic("diabetes mellitus", page_size=20)
for concept in results["concepts"]:
    print(f"{concept['concept_id']}: {concept['concept_name']}")
```

### Parameters

| Parameter           | Type       | Default  | Description                                    |
| ------------------- | ---------- | -------- | ---------------------------------------------- |
| `query`             | string     | required | Search query string                            |
| `vocabulary_ids`    | list\[str] | None     | Filter by vocabulary IDs                       |
| `domain_ids`        | list\[str] | None     | Filter by domain IDs                           |
| `concept_class_ids` | list\[str] | None     | Filter by concept class IDs                    |
| `standard_concept`  | string     | None     | Filter by standard concept ("S", "C", or None) |
| `include_synonyms`  | bool       | False    | Search in synonyms                             |
| `include_invalid`   | bool       | True     | Include invalid concepts                       |
| `min_score`         | float      | None     | Minimum relevance score (0.0-1.0)              |
| `exact_match`       | bool       | False    | Require exact match                            |
| `page`              | int        | 1        | Page number (1-based)                          |
| `page_size`         | int        | 20       | Results per page                               |
| `sort_by`           | string     | None     | Sort field                                     |
| `sort_order`        | string     | None     | Sort order ("asc" or "desc")                   |

## Filter by Vocabulary

Restrict search to specific vocabularies:

```python theme={null}
results = client.search.basic(
    "heart attack",
    vocabulary_ids=["SNOMED", "ICD10CM"],
)
```

## Filter by Domain

Search within specific domains:

```python theme={null}
results = client.search.basic(
    "aspirin",
    domain_ids=["Drug"],
    page_size=10,
)
```

## Filter by Concept Class

Search for specific concept classes:

```python theme={null}
results = client.search.basic(
    "aspirin",
    concept_class_ids=["Clinical Drug", "Ingredient"],
    page_size=10,
)
```

## Standard Concepts Only

Filter to standard concepts:

```python theme={null}
results = client.search.basic(
    "diabetes",
    standard_concept="S",  # "S" = Standard, "C" = Classification
    vocabulary_ids=["SNOMED"],
)
```

## Search with Synonyms

Include concept synonyms in search:

```python theme={null}
results = client.search.basic(
    "heart attack",
    include_synonyms=True,
    vocabulary_ids=["SNOMED"],
)
```

## Combined Filters

```python theme={null}
results = client.search.basic(
    "myocardial infarction",
    vocabulary_ids=["SNOMED"],
    domain_ids=["Condition"],
    standard_concept="S",
    include_synonyms=True,
    min_score=0.5,
    page_size=20,
)
```

## Autocomplete

Get suggestions as the user types:

```python theme={null}
result = client.search.autocomplete("diab", page_size=10)
for suggestion in result["suggestions"]:
    print(suggestion["suggestion"])
```

## Pagination

### Manual Pagination

```python theme={null}
# Get first page
results = client.search.basic("diabetes", page=1, page_size=50)

# Access pagination metadata
pagination = results["meta"]["pagination"]
print(f"Total: {pagination['total_items']}")
print(f"Pages: {pagination['total_pages']}")
print(f"Has next: {pagination['has_next']}")

# Get next page
if pagination["has_next"]:
    results = client.search.basic("diabetes", page=2, page_size=50)
```

### Auto-Pagination Iterator

Iterate through all results automatically:

```python theme={null}
count = 0
for concept in client.search.basic_iter("diabetes", page_size=100):
    print(concept["concept_name"])
    count += 1
    if count >= 500:  # Limit for demo
        break
```

## Advanced Search

Use advanced search with additional filtering options and facets:

```python theme={null}
results = client.search.advanced(
    "diabetes",
    vocabulary_ids=["SNOMED", "ICD10CM"],
    domain_ids=["Condition"],
    standard_concepts_only=True,
    page_size=50,
)

# Access results
for concept in results["data"]:
    print(f"{concept['concept_id']}: {concept['concept_name']}")

# Access pagination
print(f"Total: {results['meta']['pagination']['total_items']}")
```

### Advanced Search Parameters

| Parameter                | Type        | Default  | Description                   |
| ------------------------ | ----------- | -------- | ----------------------------- |
| `query`                  | string      | required | Search query string           |
| `vocabulary_ids`         | list\[str]  | None     | Filter by vocabulary IDs      |
| `domain_ids`             | list\[str]  | None     | Filter by domain IDs          |
| `concept_class_ids`      | list\[str]  | None     | Filter by concept class IDs   |
| `standard_concepts_only` | bool        | False    | Only return standard concepts |
| `include_invalid`        | bool        | True     | Include invalid concepts      |
| `relationship_filters`   | list\[dict] | None     | Relationship-based filters    |
| `page`                   | int         | 1        | Page number (1-based)         |
| `page_size`              | int         | 20       | Results per page              |

### Relationship Filters

Apply relationship-based filtering:

```python theme={null}
results = client.search.advanced(
    "diabetes",
    relationship_filters=[
        {"relationship_id": "Is a", "concept_id": 4116142}  # Has parent concept
    ],
    standard_concepts_only=True,
)
```

## Semantic Search

Search for concepts using natural language with neural embeddings. Semantic search understands meaning, not just keywords.

```python theme={null}
# Basic semantic search
results = client.search.semantic("heart attack", page_size=10)

# With filters
results = client.search.semantic(
    "diabetes mellitus",
    vocabulary_ids=["SNOMED"],
    domain_ids=["Condition"],
    threshold=0.5,  # Higher = more similar
    page_size=20,
)

# Access results with similarity scores
for concept in results["data"]["results"]:
    print(f"{concept['concept_name']}: {concept['similarity_score']:.2f}")
```

### Semantic Search Parameters

| Parameter          | Type       | Default  | Description                     |
| ------------------ | ---------- | -------- | ------------------------------- |
| `query`            | string     | required | Natural language search query   |
| `vocabulary_ids`   | list\[str] | None     | Filter by vocabulary IDs        |
| `domain_ids`       | list\[str] | None     | Filter by domain IDs            |
| `standard_concept` | "S" \| "C" | None     | Filter by standard concept flag |
| `concept_class_id` | string     | None     | Filter by concept class         |
| `threshold`        | float      | 0.5      | Minimum similarity (0.0-1.0)    |
| `page`             | int        | 1        | Page number                     |
| `page_size`        | int        | 20       | Results per page (max 100)      |

### Semantic Search Iterator

Iterate through all semantic search results with automatic pagination:

```python theme={null}
# Iterate through all results
for concept in client.search.semantic_iter("diabetes", page_size=50):
    print(concept["concept_name"])

# Collect first N results
import itertools
top_100 = list(itertools.islice(
    client.search.semantic_iter("diabetes"), 100
))

# With filters
for concept in client.search.semantic_iter(
    "heart failure",
    vocabulary_ids=["SNOMED"],
    threshold=0.4,
):
    print(f"{concept['concept_id']}: {concept['concept_name']}")
```

### Async Semantic Search

```python theme={null}
# Async semantic search
results = await client.search.semantic("heart attack", page_size=10)

# Async iterator
async for concept in client.search.semantic_iter("diabetes"):
    print(concept["concept_name"])
```

## Bulk Lexical Search

Search for multiple queries in a single API call (up to 50 queries). Much more efficient than individual calls when you have many terms to look up.

```python theme={null}
results = client.search.bulk_basic([
    {"search_id": "q1", "query": "diabetes mellitus"},
    {"search_id": "q2", "query": "hypertension"},
    {"search_id": "q3", "query": "aspirin"},
], defaults={"vocabulary_ids": ["SNOMED"], "page_size": 5})

for item in results["results"]:
    print(f"{item['search_id']}: {len(item['results'])} results ({item['status']})")
```

### Bulk Search Parameters

| Parameter                   | Type       | Description                      |
| --------------------------- | ---------- | -------------------------------- |
| `searches`                  | list       | List of search inputs (max 50)   |
| `searches[].search_id`      | string     | Unique ID to match results       |
| `searches[].query`          | string     | Search query                     |
| `searches[].vocabulary_ids` | list\[str] | Per-search vocabulary filter     |
| `searches[].domain_ids`     | list\[str] | Per-search domain filter         |
| `searches[].page_size`      | int        | Per-search result limit (1-100)  |
| `defaults`                  | dict       | Shared defaults for all searches |

### With Shared Defaults

```python theme={null}
# Defaults apply to all searches; per-search values override
results = client.search.bulk_basic(
    [
        {"search_id": "q1", "query": "diabetes"},
        {"search_id": "q2", "query": "heart failure"},
        {"search_id": "q3", "query": "metformin", "domain_ids": ["Drug"]},  # overrides default
    ],
    defaults={
        "vocabulary_ids": ["SNOMED"],
        "domain_ids": ["Condition"],
        "page_size": 10,
    },
)
```

## Bulk Semantic Search

Search for multiple natural-language queries using neural embeddings in a single call (up to 25 queries).

```python theme={null}
results = client.search.bulk_semantic([
    {"search_id": "s1", "query": "heart failure treatment options"},
    {"search_id": "s2", "query": "type 2 diabetes medication"},
    {"search_id": "s3", "query": "elevated blood pressure"},
], defaults={"threshold": 0.5, "page_size": 10})

for item in results["results"]:
    print(f"{item['search_id']}: {item.get('result_count', 0)} results")
    for concept in item["results"]:
        print(f"  {concept['concept_name']} ({concept['similarity_score']:.2f})")
```

### Bulk Semantic Parameters

| Parameter                   | Type       | Description                           |
| --------------------------- | ---------- | ------------------------------------- |
| `searches`                  | list       | List of search inputs (max 25)        |
| `searches[].search_id`      | string     | Unique ID to match results            |
| `searches[].query`          | string     | Natural language query (1-500 chars)  |
| `searches[].threshold`      | float      | Per-search similarity threshold (0-1) |
| `searches[].page_size`      | int        | Per-search result limit (1-50)        |
| `searches[].vocabulary_ids` | list\[str] | Per-search vocabulary filter          |
| `defaults`                  | dict       | Shared defaults for all searches      |

### Async Bulk Search

```python theme={null}
# Both bulk methods have async variants
results = await client.search.bulk_basic([...])
results = await client.search.bulk_semantic([...])
```

## Find Similar Concepts

Find concepts similar to a reference concept or query. Provide exactly one of: `concept_id`, `concept_name`, or `query`.

```python theme={null}
# By concept ID
similar = client.search.similar(concept_id=4329847)  # MI

# By concept name
similar = client.search.similar(concept_name="Type 2 diabetes mellitus")

# By natural language query
similar = client.search.similar(query="elevated blood sugar")

# With all options
similar = client.search.similar(
    concept_id=4329847,
    algorithm="semantic",  # or "lexical", "hybrid"
    similarity_threshold=0.7,
    page_size=50,
    vocabulary_ids=["SNOMED"],
    domain_ids=["Condition"],
    include_scores=True,
    include_explanations=True,
)

# Access results
for concept in similar["similar_concepts"]:
    print(f"{concept['concept_name']}: {concept['similarity_score']:.2f}")
```

### Similar Concepts Parameters

| Parameter              | Type       | Default  | Description                         |
| ---------------------- | ---------- | -------- | ----------------------------------- |
| `concept_id`           | int        | None     | Source concept ID                   |
| `concept_name`         | string     | None     | Source concept name                 |
| `query`                | string     | None     | Natural language query              |
| `algorithm`            | string     | "hybrid" | "semantic", "lexical", or "hybrid"  |
| `similarity_threshold` | float      | 0.7      | Minimum similarity (0.0-1.0)        |
| `page_size`            | int        | 20       | Max results (max 1000)              |
| `vocabulary_ids`       | list\[str] | None     | Filter by vocabulary                |
| `domain_ids`           | list\[str] | None     | Filter by domain                    |
| `standard_concept`     | string     | None     | "S", "C", or "N"                    |
| `include_invalid`      | bool       | None     | Include invalid/deprecated concepts |
| `include_scores`       | bool       | None     | Include detailed scores             |
| `include_explanations` | bool       | None     | Include similarity explanations     |

### Algorithm Comparison

| Algorithm  | Best For                 | Speed  |
| ---------- | ------------------------ | ------ |
| `semantic` | Meaning-based similarity | Slower |
| `lexical`  | Text/string similarity   | Faster |
| `hybrid`   | Balanced approach        | Medium |

### Async Similar Concepts

```python theme={null}
# Async version
similar = await client.search.similar(concept_id=4329847)
```
