Although the fill-in-the-blank concept introduced in the last section "Your First Query" is simple enough, applying it to formulate a MQL query from scratch might not be as straightforward. In this section, we walk you through all the steps to formulate queries, explain more MQL concepts, and give you a lot of tips and tricks.
Open the Query Editor in another tab or window. You'll be switching back and forth between it and this documentation.
Queries are essentially questions, just like these questions that you might ask in everyday settings:
In every question, there are some pieces of data that are already specified, and some pieces that are unknown:
| Specified | Unknown |
|---|---|
| The film The Dark Knight | Who directed that film |
| The city San Francisco | Its founding date |
| Chemical elements | Their names, symbols, and atomic masses |
| Volcanoes | Their locations |
For our purpose, the known pieces of data serve as the starting point when we formulate a query. A known piece of data in a query is usually a specific topic (e.g., The Dark Knight, San Francisco) and occasionally a class of topics (e.g., chemical elements). Thus, we can usually start formulating a query by specifying a topic or a type.
Let's formulate a query to answer, "Who directed the film The Dark Knight?"
[{ text cursor blinking here }]
"id" :
dark knight
And what it means roughly is this: consider possibly many topics whose ID is[{ "id" : "/en/the_dark_knight" }]
/en/the_dark_knight. The array [ ] means "possibly many topics".
"/en/the_dark_knight", type a comma and hit Enter to go to a new line, and hit Tab to invoke the Query Assist feature. This time, we need help looking not for a topic but for a property. The Query Assist pop-up automatically suggests the applicable properties, and you just need to locate the /film/film/directed_by property and click it.Just click the Run button below the input text box to run the query.[{ "id" : "/en/the_dark_knight", "/film/film/directed_by" : [{}] }]
That is a simple topic-based query.
Now let's write a type-based query to answer the question, "What are the names, symbols, and atomic mass of all the chemical elements?"
And put your text cursor after[{ "type" : }]
"type" : .element
/chemistry/chemical_element. Select it either by using the down arrow key to highlight it and hitting Enter, or by clicking on it. Your query should now look like this:
[{ "type" : "/chemistry/chemical_element" }]
"name" : null,. Hit Enter again for a new line.symbol and hit Enter. Type a comma and hit Enter again for a new line.atomic_mass and hit Enter. Your query should now look like this:
Note that the two properties[{ "type" : "/chemistry/chemical_element", "name" : null, "symbol" : null, "atomic_mass" : {} }]
symbol and atomic_mass belong to the type /chemistry/chemical_element, and since that type has already been specified, you don't need to spell out the full IDs of the two properties.null as the blank for filling in symbol, but it used {} for atomic_mass. This is because the symbol of a chemical element is stored as a simple string, but its atomic mass is not stored as a simple number. Its atomic mass is stored as two numbers: the atomic mass as well as a measure of uncertainty. Together, the two numbers are stored in something called a compound value, which is also given a type much as topics are given type. This kind of types, used for storing complex values, are referred to as compound value types (CVTs). We'll discuss them in depth in the Complex Values and Properties section.{} and hit Tab. Then select mass from the suggestions. You could also add uncertainty if you like.[{ "type" : "/chemistry/chemical_element", "name" : null, "symbol" : null, "atomic_mass" : { "mass" : null, "uncertainty" : null } }]
That is a simple type-based query.
Freebase contains a lot of topics, and a lot of types and properties that you yourself didn't design. This is quite different from programming on a database that you have designed, or even a database that someone on your team has designed. On Freebase, it's harder to know what data is there, and what types and properties to use to get at the data.
So far, we have relied a lot on the Query Assist feature of the Query Editor for finding IDs of topics, types, and properties. This works quite well if you already know roughly what you're looking for, but don't know precisely the IDs (of topics, types, or properties) in question. If you're less sure of what you want, then you need something in addition to Query Assist.
One method for finding what you (vaguely think you) want is to just browse and search on freebase.com. For example, if you were to search for "chemical element" on Freebase.com, chances are you'll end up at this page. You would discover that Freebase has symbols and atomic numbers for the elements. Clicking on the "Edit View" button on that page,
you can discover more properties available (to add as columns in the table view).
You can click on one of the elements, say Helium, and see all of its properties. Near the bottom of that page is an "Edit and Show details" button
that leads to this Edit page for Helium. On this second page, you can see properties that are not yet filled in for Helium. For each type, there's a button with the icon of a wrench that would lead to you to the schema page for that type. For example, clicking on the tiny wrench icon for the Chemical Element type on the Helium page,
would lead you to this schema page where you can see all the properties of that type.
You can also use the Schemas Explorer to browse domains, types, and properties in a more hierarchial manner.
So far you've seen quite a few brackets [] and braces {} in MQL queries. They are not mere JSON syntax artifacts. Rather, they have specific meanings in MQL.
Braces {} are used when you want more details or when you need to give more details. For example, consider this query asking for producers of the movie Transformers
{ "type": "/film/film", "id": "/en/transformers", "produced_by": [] }
whose result is
{ "id": "/en/transformers", "produced_by": [ "Tom DeSanto", "Don Murphy", "Lorenzo di Bonaventura", "Steven Spielberg", "Ian Bryce" ], "type": "/film/film" }
Only the names of the producers are returned. If we want more details about the producers, we can use [{}] instead of just []:
{ "type": "/film/film", "id": "/en/transformers", "produced_by": [{}] }
Essentially, this tells the MQL query engine to elaborate the data on each producer into a JSON object literal, providing the typical details at its discretion. This version of the query would now yield this result:
{ "id": "/en/transformers", "produced_by": [ { "id": "/en/tom_desanto", "name": "Tom DeSanto", "type": [ "/common/topic", "/film/producer", "/people/person", "/film/writer", "/film/director", "/film/film_story_contributor", "/influence/influence_node" ] }, { "id": "/en/don_murphy", "name": "Don Murphy", "type": [ "/common/topic", "/film/producer", "/people/person" ] }, ... ], "type": "/film/film" }
You can also demand specific details for each producer using {}. In this case, we want their date of birth and place of birth:
{ "type": "/film/film", "id": "/en/transformers", "produced_by": [{ "name": null, "/people/person/date_of_birth": null, "/people/person/place_of_birth": null }] }
Brackets [] are used where you expect possibly many results. In the preceding MQL query, since we expect many producers, we use []. If we expect only 1 result, then we don't need to use []. For example, if we know ahead of time that Transformers was directed (not produced) by only one person, then we can safely write this query (note directed\_by):
{ "type": "/film/film", "id": "/en/transformers", "directed_by": { "name": null, "/people/person/date_of_birth": null, "/people/person/place_of_birth": null } }
So you can use any of four things as blanks in your query to get data filled in, and the following table lists those four cases:
| Simple Value (string, integer) | Elaborated Details (JSON object) | |
| Zero or One Result | null |
{ } |
| Possibly Several Results | [ ] |
[ { } ] |
Note that if you are expecting only 1 result but there are several, you will get a MQL error. It is thus safest to assume that you will get several results, and almost always use either [] or [{}].
One last note about brackets and braces: they are the things that give a query its hierarchical (nesting) structure. For a query such as this one
{ "type": "/film/film", "id": "/en/transformers", "produced_by": [{ "name": null, "/people/person/date_of_birth": null, "/people/person/place_of_birth": null }], "directed_by": { "name": null, "/people/person/date_of_birth": null, "/people/person/place_of_birth": null } }
you can visualize it as a tree
with a root node (topmost) corresponding to the film and two child nodes corresponding to the producers and the director. Please keep this in mind as we'll be using the term "query nodes" subsequently.
You have seen three kinds of shortcut so far. First, an empty pair of braces {} is used where you want the MQL query engine to fill in a list of basic properties, such as name and type.
Second, properties of the /type/object type, such as /type/object/type and /type/object/name, don't have to be fully qualified at all. In fact, we haven't even mentioned that the properties type, id, guid, and name that you have seen many times are in fact properties of the /type/object type. But now you know.
Third, when a query node already has a type explicitly specified or if its type can be inferred, then you don't need to fully qualify any property of that type in the same query node. For example, instead of this
[{ "/type/object/type" : "/chemistry/chemical_element", "/type/object/name" : null, "/chemistry/chemical_element/symbol" : null, "/chemistry/chemical_element/atomic_mass" : { "/chemistry/atomic_mass/mass" : null, "/chemistry/atomic_mass/uncertainty" : null } }]
you can shorten it to
[{ "type" : "/chemistry/chemical_element", "name" : null, "symbol" : null, "atomic_mass" : { "mass" : null, "uncertainty" : null } }]
The property /chemistry/chemical_element/atomic_mass tells us that the expected type of the inner node is /chemistry/atomic_mass. You can check it using the Schemas Explorer. Because that can be inferred, we can safely shorten the properties mass and uncertainty in the inner query node.
Another kind of shortcut is the wildcard: "*" : null. Use it to get the basic properties as well as properties of the declared or expected type of a query node. For example, we can change the inner node of the preceding query like so
[{ "type" : "/chemistry/chemical_element", "name" : null, "symbol" : null, "atomic_mass" : { "*" : null } }]
and each atomic mass in the result will be filled up with /type/object properties as well as /chemistry/atomic_mass properties:
[ { "atomic_mass": { "attribution": "/user/gardening_bot/attr/66", "creator": "/user/gardening_bot/attr/66", "guid": "#9202a8c04000641f800000000ba217df", "id": "/guid/9202a8c04000641f800000000ba217df", "key": [], "name": null, "permission": "/boot/all_permission", "timestamp": "2009-04-29T04:11:49.0000Z", "type": [ "/chemistry/atomic_mass" ], "mass": 18.9984032, "uncertainty": 5e-7 }, "name": "Fluorine", "symbol": "F", "type": "/chemistry/chemical_element" }, ... ]
From what you've learned in this section of this Getting Started guide, you should be able to hunt down the types and properties you want using either freebase.com or the Schemas Explorer, and then use Query Assist in the Query Editor to formulate either a topic-based query or a type-based query. In the next section, we'll dig deeper into the concepts of constraints and joins in MQL, and you'll develop a better conceptual understanding for more complex queries.