Introduction
The DataLinks Query Language is a powerful domain-specific language designed to query and manipulate datasets within the DataLinks ecosystem. It provides a flexible and intuitive way to access data, apply filters, establish relationships between datasets, and sort results. This language is particularly useful for:- Retrieving data from specific datasets
- Filtering data based on various conditions
- Discovering relationships between different datasets
- Traversing complex data structures
- Sorting and limiting result sets
- Counting, summing, averaging and grouping records
Basic Syntax
The query language follows a fluent interface pattern, where methods are chained together to build complex queries. The basic structure of a query is:Ontology and OntologyObject are valid entry points for creating a query.
Querying Datasets
Basic Dataset Query
To query a dataset, specify its name:Ontology("movies") and Ontology("Movies") refer to the same dataset.
Namespaced Datasets
Datasets can be organized in namespaces. To query a namespaced dataset, use the format:Filtering Data
Basic Filtering
To filter data, use thefilter() method with a comparison expression:
Comparison Operators
The query language supports the following comparison operators:==(equal to)!=(not equal to)<(less than)<=(less than or equal to)>(greater than)>=(greater than or equal to)
Logical Operators
Combine multiple conditions using logical operators:&&(AND)||(OR)
Nested Conditions
Use parentheses to create complex nested conditions:Filter Expression Syntax
The query language provides flexible syntax for filter expressions:- Quoting Field Names: Field names can be unquoted, single-quoted, or double-quoted:
- Quoting Values: String values can be unquoted (for simple strings) or quoted:
- Multi-word Values: Multi-word string values must be quoted:
Note: Unquoted multi-word values (e.g.,
title == The Matrix) are not supported.Linking Datasets
Searching Related Datasets
To find related datasets, use thesearchAround() and find() methods:
Specifying Search Depth
You can specify the depth of the search (how many hops to traverse):Following Specific Links
To follow specific columns when linking datasets:Sorting and Limiting Results
Sorting Results
Sort results in ascending or descending order:Multiple Sort Criteria
Sort by multiple fields:Limiting Results
Limit the number of results returned:Aggregations
Most aggregations replace the matched records with a computed result;countLinked() and sumLinked() instead keep every record and enrich it. Place the aggregation after find() when the query traverses links, or directly after Ontology() / filter() otherwise; after it, only filter(), sortAscending() / sortDescending() and limit() may follow (plus maxDepth() for the linked aggregations). groupBy() is always paired with one count(), sum() or avg(), and that pair counts as a single aggregation. Only one aggregation is supported per query — do not combine count(), sum(), avg(), groupBy(…).<reducer>(), countLinked() or sumLinked() with each other.
Counting Records
count() returns a single number: how many records matched.
Aggregations placed directly on the root dataset are exact. After a
searchAround().find() they run over the traversed records, which are capped at 10,000 — use countLinked() / sumLinked() when you need exact per-record totals over links.Sum and Average
sum() and avg() compute a single total or average over a numeric column. The column argument is mandatory.
sum() and avg() only work on numeric columns.Grouping
groupBy() groups the matched records by the distinct values of one or more columns and returns one synthetic row per group. It must be followed by count(), sum() or avg():
groupBy("director").count()→director,count.directorgroupBy("director").sum("budget")→director,sum.budgetgroupBy("director").avg("budget")→director,avg.budget
groupBy(), sum() and avg() accept several value columns at once, producing one metric per column:
groupBy("director", "year").sum("budget")→director,year,sum.budgetgroupBy("director", "year").count()→director,year,count.director.year
distinct() operation, but groupBy("column").count() returns one row per distinct value, so the number of rows returned is the number of distinct values. At most 10,000 groups are returned (the largest by record count unless sorted), and grouping a column with more than 100,000 distinct values is rejected:
Filtering Groups
Afilter() placed before the aggregation narrows the records that get aggregated. A filter() placed after a groupBy() aggregation applies to the groups it produced, comparing against the emitted metric — the equivalent of SQL’s HAVING. Both can appear in the same query:
After a
groupBy() aggregation only the group column(s) and the metric exist on the rows. A filter that names any other column is rejected.Sorting and Limiting Groups
Sort grouped results by their metric to get the top or bottom N groups:Counting and Summing Linked Records
countLinked("X") / sumLinked("X", …) keep the matched records and add an aggregate over the linked records in X to each one. By default only direct (one-hop) links count:
_link_count: the number of movies they appear in.
sum.boxOffice.
sumLinked() accepts several numeric columns at once; each adds its own sum.<column> field:
sum.budget and sum.boxOffice.
If X is further away, add maxDepth(n). The in-between datasets are found for you, and the results stay on your original records:
sum.ticketsSold: the tickets sold across all screenings of all their movies (Actor → Movies → Screenings). Each screening counts once per actor, however many paths reach it.
To get the aggregate per record of an in-between dataset instead, traverse to it first and aggregate from there. The results then belong to that dataset, not to the one you started from:
sum.ticketsSold for that movie’s own screenings.
A filter() placed after countLinked() / sumLinked() applies to the linked dataset’s columns and restricts which linked records are counted or summed:
Unlike
groupBy() metrics, the _link_count and sum.<column> fields produced by countLinked() / sumLinked() cannot be used in a filter(). Apply any threshold on the returned rows instead.Natural Language Query Generation
The system can generate queries from natural language questions. For example: Natural language: “What is the age of the director of Braveheart?” Generated query:Examples
Basic Query Examples
- Find all movies:
- Find a specific movie:
- Find movies released before 2000:
Relationship Query Examples
- Find actors who directed movies:
- Find movies directed by actors under 60:
- Find actors who directed movies, then find other actors who worked with them:
Sorting and Limiting Examples
- Find the 3 oldest movies:
- Find the 5 highest budget movies:
Aggregation Examples
- Count movies released before 2000:
- Total budget per director, top 5:
- Directors with more than two movies:
- Movies ranked by number of linked actors:
Error Handling
If a query returns unexpected results:- Check field names and table relationships for correctness.
-
Ensure the depth in
searchAroundis sufficient for your query. - Debug by breaking the query into smaller parts and testing them individually.