Consider this very simple query:
{ "id": "/en/san_francisco", "type": [] }
It's asking, which types is the topic identified as /en/san_francisco assigned? Here is the result. If you were to think in terms of relational databases and SQL, and equate types to relational tables, then the query specifies a primary key and asks which table(s) the key belongs to.
Think how you might write such a query in SQL.
You should come to realize that it is impossible to write that query in SQL. This is because in relational database technologies, information about tables and table columns is not mixed in with the data that they store, whereas in Freebase, types and properties and data are all in the same "soup", for lack of a better word.
To get a better sense of this idea that information about types and properties (or "schema metadata") is mixed with data, let's see a few more queries about types and properties. First, let's find out the properties available on the type /business/company:
[{ "id": "/business/company", "type": "/type/type", "properties": [{ "id": null, "name": null, "expected_type": null }] }]
What's interesting about this query is that, previously, when we use /business/company in a query, it always follows "type" :, but now it follows "id" :. This is because, quite obviously, we're inquiring about the type itself, not about topics assigned that type.
Also note that every type is also assigned a type--the type /type/type. Because /business/company is assigned the type /type/type, it can have the property /type/type/properties, which lists its properties. If you find this confusing, it is OK. It takes time for these concepts to sink in.
We can also inquire about a property in a similar fashion. Here's how we might find information about the property /film/film/directed_by:
[{ "id": "/film/film/directed_by", "type": "/type/property", "schema": {}, "expected_type": {}, "reverse_property": {} }]
What's interesting about this query is that, previously, when we use /film/film/directed_by (or the abbreviated version directed_by), it's always a key in query node (before a colon), e.g.,
{ ... "/film/film/directed_by" : ... ... }
but now it's a value (after a colon)
{ ... "id" : "/film/film/directed_by" ... }
Every property is also assigned a type--the type /type/property. Because /film/film/directed_by is assigned the type /type/property, it can have the property /type/property/expected_by, which specifies the type that you can expect on all directed_by values. In this case, that expected type is /film/director.
This sort of "schema queries" are actually used to build the Schemas Explorer and the Query Editor. There is nothing magical about those tools. The magic is in the Freebase graph database. You can build similar tools once you've gotten a handle on types and properties.
Now, let's go for a more sophisticated example. Consider San Francisco the city. We want to find which properties of it would lead us to people (through direct relationships only, not through the Six Degrees of Kevin Bacon kind of relatedness). This is the query:
[{ "id": "/en/san_francisco", "type": [{ "id": null, "properties": [{ "id": null, "expected_type": { "id": "/people/person" } }] }] }]
The result will tell us that there is one such property: /location/location/people_born_here. (This is not the only property, but to get all applicable properties you would need to understand type inheritance.)
If you are familiar with relational database technologies, then you should realize that this mixing of types and properties and data is a fundamental and profound difference, and improvement. Once you've gotten used to it, you will find it very powerful and liberating. Going back to relational database technologies will feel very restrictive.
Another fundamental difference Freebase has over relational database technologies is its native support for keeping track of attribution and history. That is, whenever some piece of data is added, edited, or removed, Freebase records the user (or automated software robot) responsible for that change as well as the time that the change took place. This is just like how wikis keep track of edits.
Consider the "fact" that the name of the topic about the film The Dark Knight is, well, "The Dark Knight". As in previous sections, we would visualize that "fact" with the simple graph at the top of this diagram:
The bottom of the diagram shows the data that Freebase actually stores for that "fact". The "fact" is modeled as a (directional) link between the topic graph node and a text value. The link has a source and a target (graph node) or a target value. The other pieces of information on the link indicate that the link was inserted (into the Freebase graph) at 10:53 pm on October 23, 2006 by the software robot identified as /user/mwcl_wikipedia_en.
Although links are not graph nodes, you can still use some limited kinds of MQL queries to query about them. The MQL query engine has a special treatment for links. This query finds all the links pointing from the topic /en/the_dark_knight that were inserted since 2009:
[{ "type": "/type/link", "source": { "id": "/en/the_dark_knight" }, "target": {}, "target_value": {}, "attribution": null, "master_property": null, "operation": "insert", "timestamp>": "2009" }]
This query finds all the links pointing from /en/the_dark_knight inserted before 2007 but no longer true (they have been removed):
[{ "type": "/type/link", "source": { "id": "/en/the_dark_knight" }, "target": {}, "target_value": {}, "attribution": null, "master_property": null, "operation": "insert", "timestamp<": "2007", "valid": false }]
Freebase's edit tracking allows us to provide an extremely neat, mind-blowing feature: querying as of a particular time. That is, given a particular date/time, the MQL query engine can evaluate a query against the state of Freebase at that time (rather than at the current time). It's as if you go back in time and run the query. To see how this works, copy and paste this query into the Query Editor and run it:
[{ "type": "/government/us_president", "name": null, "presidency_number": { "value": null, "sort": "-value", "limit": 1 }, "sort": "-presidency_number.value" }]
This query returns all the US presidents sorted from latest to earliest. At this time of writing (July 2009), Barack Obama is the first result. Now, in the Control Panel at the bottom of the Query Editor, switch to the Envelope tab, and enter into the as_of_time text box
2008-01-01
and run the query again. Now George W. Bush is the first result. This is because, as of January 1, 2008, the "latest" US president was George W. Bush. At that time, nobody in the universe, including Freebase, knew that Barack Obama would become the next US president.
This "as of time" querying capability is not just a neat feature to impress your geek friends at coding parties, it also has practical use. If you have just verified that Freebase is containing precisely the data you want for some application that you're building, then you can effectively "freeze" the data by making your application dispatch queries as of the time you did the verification. Your application won't see any change made to Freebase after that time. Hence, changes by other users that are undesirable for your application do not affect your application at all.
Alas, "as of time" works only with a past timestamp. We haven't figured out how to make Freebase see into the future.
You might have noticed in the diagram above that the text value "The Dark Knight" is marked with the language the text is written in, English in this case. Freebase has native internationalization support for text values. By default, for simplicity, the MQL query engine assumes one particular language (English) and only returns text values in that language. But you can request for all text values regardless of their languages. For example, we can get the names of the continent known as Asia (in English) in many other languages with this simple query:
[{ "id": "/en/asia", "name": [{}] }]
This language support makes it a bit more believable if we were to audaciously call Freebase "the World's database".