Skip to main content

Your First Query

For Everyone

Now that you have a cube defined, let's query it! Olytix Core provides multiple ways to access your semantic layer: REST API, GraphQL, and Python SDK.

Prerequisites

Make sure you have:

  1. A Olytix Core project with at least one cube defined
  2. The Olytix Core server running (olytix-core serve)

Understanding Semantic Queries

Unlike traditional SQL, semantic queries use business concepts:

Traditional SQL:
SELECT region, SUM(total_amount)
FROM orders
GROUP BY region

Semantic Query:
{
"measures": ["orders.total_revenue"],
"dimensions": ["orders.region"]
}

The semantic layer handles:

  • Generating optimal SQL
  • Applying joins automatically
  • Enforcing security rules
  • Caching and optimization

REST API Queries

Basic Query

curl -X POST http://localhost:8000/api/v1/query \
-H "Content-Type: application/json" \
-d '{
"measures": ["orders.total_revenue", "orders.count"],
"dimensions": ["orders.region"]
}'

Response:

{
"data": [
{ "orders.region": "NORTH", "orders.total_revenue": 250000.00, "orders.count": 3200 },
{ "orders.region": "SOUTH", "orders.total_revenue": 180000.00, "orders.count": 2100 },
{ "orders.region": "EAST", "orders.total_revenue": 320000.00, "orders.count": 4500 },
{ "orders.region": "WEST", "orders.total_revenue": 275000.00, "orders.count": 3800 }
],
"query": {
"sql": "SELECT UPPER(region) AS region, SUM(total_amount) AS total_revenue, COUNT(*) AS count FROM fct_orders GROUP BY UPPER(region)",
"duration_ms": 45
}
}

Adding Filters

Filter your data using the filters parameter:

curl -X POST http://localhost:8000/api/v1/query \
-H "Content-Type: application/json" \
-d '{
"measures": ["orders.total_revenue"],
"dimensions": ["orders.status"],
"filters": [
{
"dimension": "orders.region",
"operator": "equals",
"value": "NORTH"
},
{
"dimension": "orders.order_date",
"operator": "gte",
"value": "2024-01-01"
}
]
}'

Filter Operators

OperatorDescriptionExample
equalsExact match"value": "completed"
notEqualsNot equal"value": "cancelled"
containsString contains"value": "ship"
gt, gteGreater than (or equal)"value": 100
lt, lteLess than (or equal)"value": 1000
inListIn array"value": ["A", "B"]
notInListNot in array"value": ["X", "Y"]
betweenRange"value": [10, 100]
setIs not null(no value needed)
notSetIs null(no value needed)

Time Dimension Queries

Query by time with granularity:

curl -X POST http://localhost:8000/api/v1/query \
-H "Content-Type: application/json" \
-d '{
"measures": ["orders.total_revenue", "orders.count"],
"dimensions": ["orders.order_date.month"],
"filters": [
{
"dimension": "orders.order_date.year",
"operator": "equals",
"value": 2024
}
],
"order_by": [
{ "field": "orders.order_date.month", "direction": "asc" }
]
}'

Response:

{
"data": [
{ "orders.order_date.month": "2024-01", "orders.total_revenue": 125000.00, "orders.count": 1523 },
{ "orders.order_date.month": "2024-02", "orders.total_revenue": 142000.00, "orders.count": 1687 },
{ "orders.order_date.month": "2024-03", "orders.total_revenue": 158000.00, "orders.count": 1892 }
]
}

Ordering and Limiting

Control result ordering and pagination:

curl -X POST http://localhost:8000/api/v1/query \
-H "Content-Type: application/json" \
-d '{
"measures": ["orders.total_revenue"],
"dimensions": ["orders.customer_id"],
"order_by": [
{ "field": "orders.total_revenue", "direction": "desc" }
],
"limit": 10,
"offset": 0
}'

GraphQL Queries

Olytix Core also exposes a GraphQL endpoint for more flexible querying.

Basic GraphQL Query

query GetOrdersByRegion {
query(
measures: ["orders.total_revenue", "orders.count"]
dimensions: ["orders.region"]
) {
data
query {
sql
duration_ms
}
}
}

Using curl:

curl -X POST http://localhost:8000/graphql \
-H "Content-Type: application/json" \
-d '{
"query": "query { query(measures: [\"orders.total_revenue\"], dimensions: [\"orders.region\"]) { data } }"
}'

GraphQL with Variables

query GetOrders($measures: [String!]!, $dimensions: [String!]!, $filters: [FilterInput!]) {
query(measures: $measures, dimensions: $dimensions, filters: $filters) {
data
query {
sql
}
}
}

Variables:

{
"measures": ["orders.total_revenue"],
"dimensions": ["orders.status"],
"filters": [
{
"dimension": "orders.region",
"operator": "equals",
"value": "NORTH"
}
]
}

Exploring the Schema

Access the GraphQL Playground at http://localhost:8000/graphql to:

  • Browse available queries
  • See all cubes, measures, and dimensions
  • Test queries interactively

Python SDK

For Python applications, use the Olytix Core client:

Installation

pip install olytix-core-client

Basic Usage

from olytix-core import Olytix CoreClient

# Connect to Olytix Core
client = Olytix CoreClient("http://localhost:8000")

# Simple query
result = client.query(
measures=["orders.total_revenue", "orders.count"],
dimensions=["orders.region"]
)

# Access data
for row in result.data:
print(f"{row['orders.region']}: ${row['orders.total_revenue']:,.2f}")

Query with Filters

from olytix-core import Olytix CoreClient, Filter

client = Olytix CoreClient("http://localhost:8000")

result = client.query(
measures=["orders.total_revenue"],
dimensions=["orders.status", "orders.order_date.month"],
filters=[
Filter("orders.region", "equals", "NORTH"),
Filter("orders.order_date", "gte", "2024-01-01"),
],
order_by=[("orders.order_date.month", "asc")],
limit=12
)

print(result.data)
print(f"Query took {result.query.duration_ms}ms")

Pandas Integration

import pandas as pd
from olytix-core import Olytix CoreClient

client = Olytix CoreClient("http://localhost:8000")

# Get data as DataFrame
df = client.query(
measures=["orders.total_revenue", "orders.count"],
dimensions=["orders.order_date.month"]
).to_dataframe()

# Now use pandas for analysis
df['avg_order_value'] = df['orders.total_revenue'] / df['orders.count']
print(df.describe())

Async Queries

For large datasets, use async queries:

import asyncio
from olytix-core import Olytix CoreClient

async def main():
client = Olytix CoreClient("http://localhost:8000")

# Start async query
job = await client.query_async(
measures=["orders.total_revenue"],
dimensions=["orders.customer_id"]
)

# Check status
while not job.is_complete:
print(f"Progress: {job.progress}%")
await asyncio.sleep(1)
await job.refresh()

# Get results
result = await job.get_result()
print(f"Got {len(result.data)} rows")

asyncio.run(main())

Query Examples

Top Customers by Revenue

curl -X POST http://localhost:8000/api/v1/query \
-H "Content-Type: application/json" \
-d '{
"measures": ["orders.total_revenue", "orders.count"],
"dimensions": ["orders.customer_id"],
"order_by": [{ "field": "orders.total_revenue", "direction": "desc" }],
"limit": 10
}'

Monthly Revenue Trend

curl -X POST http://localhost:8000/api/v1/query \
-H "Content-Type: application/json" \
-d '{
"measures": ["orders.total_revenue"],
"dimensions": ["orders.order_date.month"],
"filters": [
{
"dimension": "orders.order_date.year",
"operator": "equals",
"value": 2024
}
],
"order_by": [{ "field": "orders.order_date.month", "direction": "asc" }]
}'

Revenue by Region and Status

curl -X POST http://localhost:8000/api/v1/query \
-H "Content-Type: application/json" \
-d '{
"measures": ["orders.total_revenue", "orders.avg_order_value"],
"dimensions": ["orders.region", "orders.status"],
"filters": [
{
"dimension": "orders.status",
"operator": "notEquals",
"value": "cancelled"
}
]
}'

Orders in Date Range

curl -X POST http://localhost:8000/api/v1/query \
-H "Content-Type: application/json" \
-d '{
"measures": ["orders.count"],
"dimensions": ["orders.order_date.day"],
"filters": [
{
"dimension": "orders.order_date",
"operator": "between",
"value": ["2024-01-01", "2024-01-31"]
}
]
}'

Understanding Query Response

Every query returns:

{
"data": [...], // The result rows
"query": {
"sql": "...", // Generated SQL
"duration_ms": 45 // Execution time
},
"meta": {
"total_rows": 100, // Total available rows
"returned_rows": 10, // Rows in this response
"cached": false // Whether result was cached
}
}

Error Handling

Invalid Measure/Dimension

{
"error": {
"code": "INVALID_MEASURE",
"message": "Measure 'orders.invalid_measure' not found",
"available_measures": ["orders.count", "orders.total_revenue", "orders.avg_order_value"]
}
}

Invalid Filter

{
"error": {
"code": "INVALID_FILTER",
"message": "Operator 'like' is not valid for dimension type 'number'",
"valid_operators": ["equals", "notEquals", "gt", "gte", "lt", "lte", "between"]
}
}

Next Steps

Now that you can query your semantic layer:

  1. Create your first model →
  2. Learn about time intelligence →
  3. Set up pre-aggregations for performance →
  4. Connect BI tools →