So we have been developing some graph based analysis tools, using neo4j as a persistence engine in the background. As part of this we are developing a graph data model suitable for our domain, and we want to use this in the application layer to restrict the types of nodes, or to ensure that nodes of certain types must carry certain properties. Normal data model restrictions.
So thats the background, what I am asking is if there is some standard way to represent a data-model for a graph db? The graph equivalent of an xsd perhaps?
There's an open-source project supporting strong schema definitions in Neo4j: Structr (http://structr.org, see it in action: http://vimeo.com/structr/videos)
With Structr, you can define an in-graph schema of your data model including
Type inheritance
Supported data types: Boolean, String, Integer, Long, Double, Date, Enum (+ values)
Default values
Cardinality (1:1, 1:*, *:1)
Not-null constraints
Uniqueness constraints
Full type safety
Validation
Cardinality enforcement
Support for methods (custom action) is currently being added to the schema.
The schema can be edited with an editor, or directly via REST, modifiying the JSON representation of the data model:
{
"query_time": "0.001618446",
"result_count": 4,
"result": [
{
"name": "Whisky",
"extendsClass": null,
"relatedTo": [
{
"id": "96d05ddc9f0b42e2801f06afb1374458",
"name": "Flavour"
},
{
"id": "28f85dca915245afa3782354ea824130",
"name": "Location"
}
],
"relatedFrom": [],
"id": "df9f9431ed304b0494da84ef63f5f2d8",
"type": "SchemaNode",
"_name": "String"
},
{
"name": "Flavour",
...
},
{
"name": "Location",
...
},
{
"name": "Region",
...
}
],
"serialization_time": "0.000829985"
}
{
"query_time": "0.001466743",
"result_count": 3,
"result": [
{
"name": null,
"sourceId": "28f85dca915245afa3782354ea824130",
"targetId": "e4139c5db45a4c1cbfe5e358a84b11ed",
"sourceMultiplicity": null,
"targetMultiplicity": "1",
"sourceNotion": null,
"targetNotion": null,
"relationshipType": "LOCATED_IN",
"sourceJsonName": null,
"targetJsonName": null,
"id": "d43902ad7348498cbdebcd92135926ea",
"type": "SchemaRelationship",
"relType": "IS_RELATED_TO"
},
{
"name": null,
"sourceId": "df9f9431ed304b0494da84ef63f5f2d8",
"targetId": "96d05ddc9f0b42e2801f06afb1374458",
"sourceMultiplicity": null,
"targetMultiplicity": "1",
"sourceNotion": null,
"targetNotion": null,
"relationshipType": "HAS_FLAVOURS",
"sourceJsonName": null,
"targetJsonName": null,
"id": "bc9a6308d1fd4bfdb64caa355444299d",
"type": "SchemaRelationship",
"relType": "IS_RELATED_TO"
},
{
"name": null,
"sourceId": "df9f9431ed304b0494da84ef63f5f2d8",
"targetId": "28f85dca915245afa3782354ea824130",
"sourceMultiplicity": null,
"targetMultiplicity": "1",
"sourceNotion": null,
"targetNotion": null,
"relationshipType": "PRODUCED_IN",
"sourceJsonName": null,
"targetJsonName": null,
"id": "a55fb5c3cc29448e99a538ef209b8421",
"type": "SchemaRelationship",
"relType": "IS_RELATED_TO"
}
],
"serialization_time": "0.000403616"
}
You can access nodes and relationships stored in Neo4j as JSON objects through a RESTful API which is dynamically configured based on the in-graph schema.
$ curl try.structr.org:8082/structr/rest/whiskies?name=Ardbeg
{
"query_time": "0.001267211",
"result_count": 1,
"result": [
{
"flavour": {
"name": "J",
"description": "Full-Bodied, Dry, Pungent, Peaty and Medicinal, with Spicy, Feinty Notes.",
"id": "626ba892263b45e29d71f51889839ebc",
"type": "Flavour"
},
"location": {
"region": {
"name": "Islay",
"id": "4c7dd3fe2779492e85bdfe7323cd78ee",
"type": "Region"
},
"whiskies": [
...
],
"name": "Port Ellen",
"latitude": null,
"longitude": null,
"altitude": null,
"id": "47f90d67e1954cc584c868e7337b6cbb",
"type": "Location"
},
"name": "Ardbeg",
"id": "2db6b3b41b70439dac002ba2294dc5e7",
"type": "Whisky"
}
],
"serialization_time": "0.010824154"
}
In the UI, there's also a data editing (CRUD) tool, and CMS components supporting to create web applications on Neo4j.
Disclaimer: I'm a developer of Structr and founder of the project.
No, there's no standard way to do this. Indeed, even if there were, keep in mind that the only constraints that neo4j currently supports are uniqueness constraints.
Take for example some sample rules:
All nodes labeled :Person must have non-empty properties fname and lname
All nodes labeled :Person must have >= 1 outbound relationship of type :works_for
The trouble with the present neo4j is that even in the case where you did have a schema language (standardized) that could express these things, there wouldn't be a way that the db engine itself could actually enforce that constraint.
So the simple answer is no, there's no standard way of doing that right now.
A few tricks I've seen people use to simulate the same:
Assemble a list of "test suite" cypher queries, with known results. Query for things you know shouldn't be there; non-empty result sets are a sign of a problem/integrity violation. Query for things you know should be there; empty result sets are a problem.
Application-level control -- via some layer like spring-data or similar, control who can talk to the database. This essentially moves your data integrity/testing problem up into the app, away from the database.
It's a common (and IMHO annoying) aspect of many NoSQL solutions (not specifically neo4j) that because of their schema-weakness, they tend to force validation up the tech stack into the application. Doing these things in the application tends to be harder and more error-prone. SQL databases permit you to implement all sorts of schema constraints, triggers, etc -- specifically to make it really damn hard to put the wrong data into the database. The NoSQL databases typically either aren't there yet, or don't do this as a design decision. There are indeed flexibility/performance tradeoffs. Databases can insert faster and be more flexible to adapt quickly if they aren't burdened with checking each atom of data against a long list of schema rules.
EDIT: Two relevant resources: the metagraphs proposal talks about how you could represent the schema as a graph, and neoprofiler is an application that attempts to infer the actual structure of a neo4j database and show you its "profile".
With time, I think it's reasonable to hope that neo would include basic integrity features like requiring certain labels to have certain properties (the example above), restricting the data types of certain properties (lname must always be a String, never an integer), and so on. The graph data model is a bit wild and wooly though (in the computational complexity sense) and there are some constraints on graphs that people desperately would want, but will probably never get. An example would be the constraint that a graph can't have cycles in it. Enforcing that on the creation of every relationship would be very computationally intensive. (
I am sending the following mql query to get a list of topics, their mids and "notable types", but in the results notable types are always empty.
[{
"name": "The beatles",
"/common/topic/notable_types": [], //also tried "null"
"mid": null,
"limit": 10
}]
But this is inconsistent with the online freebase. For example, the query returns
{
"mid": "/m/07c0j",
"/common/topic/notable_types": [],
"name": "The Beatles"
},
And by checking the webpage "http://www.freebase.com/m/07c0j" you can see it has a notable type of "music artist".
Any suggestions if I have used wrong query or anything to do with the freebase database?
Many thanks!
They should really return on error on this query. Notably types isn't available through the MQL API -- only the Topic API.
I'm having a hard time trying to get data about a person from Freebase using his social link - by a MQL query.
How could this be done?
Something like:
https://www.googleapis.com/freebase/v1/mqlread?query={
"*":[{}],
"/common/topic/social_media_presence":[{
"value":"http://twitter.com/JustinBieber"
}]
}
Those links are really stored as keys and the links are generated from templates with they key plugged in. You can see all the keys here: https://www.freebase.com/m/06w2sn5?keys=
A modified version of your query would be:
[{
"key": [{
"namespace": {
"id": "/authority/twitter"
},
"value": "JustinBieber"
}],
"*": [{}]
}]
You can do the same thing with other namespaces like /authority/facebook or /authority/musicbrainz as well as the various language wikipedias e.g. /wikipedia/en
I'm not sure how complete the coverage or currency of the social media info is though...
I'm trying to find the best way to get the information displayed on a Freebase page via a MQL query.
I've tried the topic API but that includes a lot of metadata.
I've also tried using links/reflection as in:
{
"id": "/en/samsung_electronics",
"/type/reflect/any_master": [{
"link": {
"master_property": null
},
"name": null,
"id": null
}],
"/type/reflect/any_reverse": [{
"link": {
"master_property": null
},
"name": null,
"id": null
}],
"/type/reflect/any_value": [{
"link": {
"master_property": null
},
"value": null
}]
}
But that means I'll be missing some information, such as the number of employees because that's given as a "Dated Integer" which, of course, doesn't get automatically expanded and I won't know what I would have to expand in general. My best attempts at expanding all objects by nesting that query once in itself were met with a
"code": 503,
"message": "Backend Error"
In RDF/SPARQL (e.g. DBpedia) I'd just do select ?p ?o where {URI ?p ?o} and select ?s ?p where {?s ?p URI}, am I missing such a simple way to do this in Freebase?
So to summarize, I'm looking for a way to get the information on a Freebase HTML page with as little overhead as possible and without missing anything.
The Topic API was designed specifically for this use case (and is what's used to construct the Freebase HTML page). It takes a filter parameter which can be used to tailor its output to include only parts of the schema which are of interest. What metadata is getting in your way? Why can't you just skip it?
If you'd prefer to use SPARQL, there's an RDF dump available that you could load in your own triple store and query with SPARQL.
I would like to develop a Freebase java application that lets you browse Freebase.
I thought a good starting point would be to mimic the Freebase Schema Explorer and allow the user of my app to "drill down" through Domains, Types in a Domain, then Instances in a Type.
Can someone please assist in how you retrieve a List of domains?
Then a list in that domain? etc...
The user can then select a domain and i would like to preset a list of types within that domain and so on until they have found the entry or entries they are investigating.
MQL for domains:
[{
"id": null,
"name": null,
"type": "/type/domain",
"!/freebase/domain_category/domains": {
"id": "/category/commons"
}
}]
The "!/freebase/domain_category/domains" clause in there is to restrict things to just the Commons (official) domains - otherwise you get the domain which is automatically created for every user and probably isn't what you're after.
Types in a domain:
[{
"id": null,
"name": null,
"type": "/type/type",
"domain": "/cvg"
}]
Replace "/cvg" as appropriate.
Instances of a type:
[{
"id": null,
"name": null,
"type": "/cvg/computer_videogame"
}]
Replace "/cvg/computer_videogame" as appropriate.
This should at least get you started.