Multi-Dimensional Extraction
Multi-Dimensional Extraction lets you define a column schema and have the AI extract table-like rows from indexed documents. Files must be indexed as EliseFiles first — see File Indexation.
How It Works
Multi-dimensional extraction runs as an asynchronous job, like Question Answering and Extraction. You submit target files and a schema, poll the job, then retrieve rows and cells when it completes.
Use regular Extraction when you need a fixed set of independent metadata fields. Use Multi-Dimensional Extraction when each result is a row with multiple related cells, such as compounds, interventions, sites, timepoints, or measurements.
Creating a Multi-Dimensional Extraction Job
Optionally pass a config object (JobLaunchConfig) to control how unindexed input files are handled. By default, the request fails if any file is not indexed. Set skip_unindexed_files: true to exclude them instead. See Common Patterns: Job Launch Config.
- cURL
- Python (httpx)
- R
- SDK
curl -X POST "https://<api-domain>/api/core/multi-dim-extraction/jobs" \
-H "Authorization: Bearer <your-pat>" \
-H "Content-Type: application/json" \
-d '{
"files": {
"fileIds": ["a1b2c3d4-e5f6-7890-abcd-ef1234567890"],
"collectionIds": []
},
"schema": {
"name": "compounds",
"description": "Compounds studied in the source documents and their administered doses",
"columns": [
{
"key": "compound",
"label": "Compound",
"type": "ENTITY_COLUMN_TYPE_STRING",
"role": "ENTITY_COLUMN_ROLE_IDENTIFIER",
"description": "Compound or treatment name",
"isRowKey": true
},
{
"key": "dose",
"label": "Dose",
"type": "ENTITY_COLUMN_TYPE_FLOAT",
"role": "ENTITY_COLUMN_ROLE_VALUE"
}
]
}
}'
response = client.post(
"/multi-dim-extraction/jobs",
json={
"files": {
"fileIds": ["a1b2c3d4-e5f6-7890-abcd-ef1234567890"],
"collectionIds": [],
},
"schema": {
"name": "compounds",
"description": "Compounds studied in the source documents and their administered doses",
"columns": [
{
"key": "compound",
"label": "Compound",
"type": "ENTITY_COLUMN_TYPE_STRING",
"role": "ENTITY_COLUMN_ROLE_IDENTIFIER",
"description": "Compound or treatment name",
"isRowKey": True,
},
{
"key": "dose",
"label": "Dose",
"type": "ENTITY_COLUMN_TYPE_FLOAT",
"role": "ENTITY_COLUMN_ROLE_VALUE",
},
],
},
},
)
response.raise_for_status()
job = response.json()
print(f"Job created: {job['jobId']} ({job['status']})")
resp <- base_req |>
req_url_path_append("multi-dim-extraction", "jobs") |>
req_body_json(list(
files = list(
fileIds = list("a1b2c3d4-e5f6-7890-abcd-ef1234567890"),
collectionIds = list()
),
schema = list(
name = "compounds",
description = "Compounds studied in the source documents and their administered doses",
columns = list(
list(
key = "compound",
label = "Compound",
type = "ENTITY_COLUMN_TYPE_STRING",
role = "ENTITY_COLUMN_ROLE_IDENTIFIER",
description = "Compound or treatment name",
isRowKey = TRUE
),
list(
key = "dose",
label = "Dose",
type = "ENTITY_COLUMN_TYPE_FLOAT",
role = "ENTITY_COLUMN_ROLE_VALUE"
)
)
)
)) |>
req_perform()
job <- resp_body_json(resp)
cat(sprintf("Job created: %s (status: %s)\n", job$jobId, job$status))
import asyncio
from biolevate import BiolevateClient, EntityColumnInput, EntitySchemaInput
async def main():
async with BiolevateClient(
base_url="https://<api-domain>",
token="<your-pat>",
) as client:
schema = EntitySchemaInput(
name="compounds",
description="Compounds studied in the source documents and their administered doses",
columns=[
EntityColumnInput(
key="compound",
label="Compound",
type="ENTITY_COLUMN_TYPE_STRING",
role="ENTITY_COLUMN_ROLE_IDENTIFIER",
is_row_key=True,
),
EntityColumnInput(
key="dose",
label="Dose",
type="ENTITY_COLUMN_TYPE_FLOAT",
role="ENTITY_COLUMN_ROLE_VALUE",
),
],
)
job = await client.mde.create_job(
schema=schema,
file_ids=["a1b2c3d4-e5f6-7890-abcd-ef1234567890"],
)
print(f"Job created: {job.job_id} (status: {job.status})")
asyncio.run(main())
Schema Object
| Field | Description |
|---|---|
name | Short, machine-friendly name of the entity schema (for example, compounds) |
description | Natural-language description of what the table represents, giving the AI extra context |
columns | The list of columns to extract for each row (see below) |
A concise schema description complements the per-column label, description, and role. Omit it when the name and columns are already self-explanatory.
Schema Fields
Each schema column is an EliseEntityColumnInput.
| Field | Required | Description |
|---|---|---|
key | Yes | Stable machine-readable column identifier |
label | No | Human-readable column name |
type | No | One of ENTITY_COLUMN_TYPE_STRING, INT, FLOAT, or BOOL |
role | No | Semantic role such as IDENTIFIER, GROUP, VALUE, or UNIT |
description | No | Extra instructions for the AI |
allowedValues | No | Restrict values for enum-like columns |
isRowKey | No | Whether this column helps identify unique rows |
Column Roles
The optional role field explains the semantic function of a column, beyond its type and isRowKey value. It helps the backend understand how columns relate to each other: which columns identify rows, scope measurements, contain measured values, or provide context.
If you are not sure which role applies, you can omit role entirely or use ENTITY_COLUMN_ROLE_UNSPECIFIED. The backend can still infer intent from key, label, description, type, and isRowKey.
Prefer leaving role unspecified over guessing. A precise description is often more useful than an incorrect role.
| Role | Use when | Impact |
|---|---|---|
ENTITY_COLUMN_ROLE_UNSPECIFIED | The caller does not know, or does not want to specify, the semantic role. | The backend infers the role from the rest of the schema. |
ENTITY_COLUMN_ROLE_IDENTIFIER | The column contains a stable ID, code, acronym, accession number, DOI, NCT ID, PMID, registry ID, or similar identifier. | Helps recognize the same entity across rows or documents. Usually pairs well with isRowKey: true. |
ENTITY_COLUMN_ROLE_LABEL | The column contains a human-readable name or display label. | Helps produce readable outputs, but does not imply the value is unique or stable. |
ENTITY_COLUMN_ROLE_GROUP | The column identifies a group, arm, cohort, population, subgroup, category, sex, age group, or severity group. | Scopes measured values, for example "response rate for placebo at Week 12". Often part of the row key. |
ENTITY_COLUMN_ROLE_TIMEPOINT | The column indicates when the measurement was observed: week, visit, cycle, month, day, or follow-up window. | Helps align repeated measures over time. Often part of the row key. |
ENTITY_COLUMN_ROLE_VALUE | The column contains the measured value itself: number, score, percentage, count, ratio, p-value, or textual result. | Marks the main extracted result. Usually isRowKey: false. |
ENTITY_COLUMN_ROLE_UNIT | The column contains a unit, scale, or symbol separated from the value. | Helps interpret adjacent VALUE columns correctly. |
ENTITY_COLUMN_ROLE_DEFINITION | The column defines a concept, criterion, endpoint, threshold, rule, or inclusion condition. | Adds explanatory semantics rather than a raw measurement. |
ENTITY_COLUMN_ROLE_COMMENT | The column contains notes, caveats, footnotes, extraction comments, or additional context. | Preserves contextual information without treating it as an identifier or primary value. |
Common examples:
| Scenario | Typical role |
|---|---|
NCT01234567, PMID: 12345678, 10.1056/... | ENTITY_COLUMN_ROLE_IDENTIFIER |
Secukinumab 300 mg, Primary endpoint, Clinical response | ENTITY_COLUMN_ROLE_LABEL |
Placebo, Male, Age < 65, Moderate-to-severe patients | ENTITY_COLUMN_ROLE_GROUP |
Baseline, Week 12, Month 6, 52-week follow-up | ENTITY_COLUMN_ROLE_TIMEPOINT |
42%, 12.4, 0.72, p < 0.001, Not reported | ENTITY_COLUMN_ROLE_VALUE |
mg, %, events/person-year, mmHg, points | ENTITY_COLUMN_ROLE_UNIT |
At least 50% reduction from baseline | ENTITY_COLUMN_ROLE_DEFINITION |
Approximate value read from figure | ENTITY_COLUMN_ROLE_COMMENT |
Rule of Thumb
- If it is a measured result, use
ENTITY_COLUMN_ROLE_VALUE. - If it answers "for which group?", use
ENTITY_COLUMN_ROLE_GROUP. - If it answers "when?", use
ENTITY_COLUMN_ROLE_TIMEPOINT. - If it is a stable ID or code, use
ENTITY_COLUMN_ROLE_IDENTIFIER. - If it is a human-readable name, use
ENTITY_COLUMN_ROLE_LABEL. - If it is a unit or scale, use
ENTITY_COLUMN_ROLE_UNIT. - If it defines a concept or criterion, use
ENTITY_COLUMN_ROLE_DEFINITION. - If it is a note or caveat, use
ENTITY_COLUMN_ROLE_COMMENT. - If you are not sure, omit
roleor useENTITY_COLUMN_ROLE_UNSPECIFIED.
Example
{
"name": "ClinicalOutcome",
"columns": [
{
"key": "trial_id",
"label": "Trial ID",
"type": "ENTITY_COLUMN_TYPE_STRING",
"role": "ENTITY_COLUMN_ROLE_IDENTIFIER",
"isRowKey": true
},
{
"key": "treatment_arm",
"label": "Treatment arm",
"type": "ENTITY_COLUMN_TYPE_STRING",
"role": "ENTITY_COLUMN_ROLE_GROUP",
"isRowKey": true
},
{
"key": "week",
"label": "Week",
"type": "ENTITY_COLUMN_TYPE_STRING",
"role": "ENTITY_COLUMN_ROLE_TIMEPOINT",
"isRowKey": true
},
{
"key": "response_rate",
"label": "Response rate (%)",
"type": "ENTITY_COLUMN_TYPE_FLOAT",
"role": "ENTITY_COLUMN_ROLE_VALUE",
"isRowKey": false
},
{
"key": "note",
"label": "Note",
"type": "ENTITY_COLUMN_TYPE_STRING",
"role": "ENTITY_COLUMN_ROLE_COMMENT",
"isRowKey": false
}
]
}
Polling Job Status
curl -s "https://<api-domain>/api/core/multi-dim-extraction/jobs/${JOB_ID}" \
-H "Authorization: Bearer <your-pat>"
Poll until status is SUCCESS, FAILED, or ABORTED.
Retrieving Results
curl -s "https://<api-domain>/api/core/multi-dim-extraction/jobs/${JOB_ID}/results" \
-H "Authorization: Bearer <your-pat>"
The response contains entityExtraction.rows. Each row contains cells, and each cell has:
| Field | Description |
|---|---|
columnKey | Column key from the submitted schema |
value | Extracted value |
explanation | Optional explanation for the cell value |
referenceIds | Source annotation IDs supporting the value |
Inputs and Annotations
Use these endpoints to inspect the original request and resolve source passages:
curl -s "https://<api-domain>/api/core/multi-dim-extraction/jobs/${JOB_ID}/inputs" \
-H "Authorization: Bearer <your-pat>"
curl -s "https://<api-domain>/api/core/multi-dim-extraction/jobs/${JOB_ID}/annotations" \
-H "Authorization: Bearer <your-pat>"
See Annotations for the shared annotation object model.
Listing Jobs
curl -s "https://<api-domain>/api/core/multi-dim-extraction/jobs?page=0&pageSize=20" \
-H "Authorization: Bearer <your-pat>"
Next Steps
- Python SDK: Multi-Dimensional Extraction — high-level SDK methods
- Extraction — fixed metadata field extraction
- Annotations — source passages for extracted cells