levelgraph / levelgraph-jsonld

The Object Document Mapper for LevelGraph based on JSON-LD
113 stars 16 forks source link

Document meaning of db.('webid') in the search example #62

Closed kristianmandrup closed 7 years ago

kristianmandrup commented 7 years ago

Where can I find the API for db.v('webid')?

  db.search([{
    subject: manu['@id'],
    predicate: 'http://xmlns.com/foaf/0.1/knows',
    object: db.v('webid')
  }, {
    subject: db.v('webid'),

I see another example on the levelgraph Readme, so now I guess it is just a way to indicate which subjects should match which objects and such in the query. Makes sense, reminds me of Datomic from ClojureScript, using q? convention to the same effect... Would be nice if that was documented in the examples. Thanks :)

  var stream = db.searchStream([{
    subject: "matteo",
    predicate: "friend",
    object: db.v("x")
  }, {
    subject: db.v("x"),
BigBlueHat commented 7 years ago

db.v() is a way to define a Variable within a LevelGraph search: https://github.com/mcollina/levelgraph#searches

The webid or x in the examples above will become a key name in the search results.

What other documentation would you like to see?

BigBlueHat commented 7 years ago

@kristianmandrup you might also dig around in here: https://github.com/warpr/turtle-to-jsonld/blob/master/lib/turtle-to-jsonld.js#L213-L235

Lots of handy utility things in that project that would be nice to see up-streamed and/or extracted eventually.

Cheers! 🎩

kristianmandrup commented 7 years ago

Thanks! I will take a look :)

How does jsonld deal with circular refs? I would assume it just "links" to nodes that only have the @id?

{
  "@id": "mark",
  "name": "mark",
  "gender": "male",
  "self": {
    "@id": "mark"
  }
}
BigBlueHat commented 7 years ago

The triples for that look like this:

<mark> <gender> "male" .
<mark> <name> "mark" .
<mark> <self> <mark> .

Triples are just sentences (conceptually): Subject, Predicate, Object. So, you're basically saying "mark is mark--which is valid, but a bit unnecessary. 😃

Here's some valid JSON-LD (adds a @context) in the JSON-LD Playground for you to checkout.

Make sense?

kristianmandrup commented 7 years ago

Thanks, I'm slowly progressing...

save {
  "@context": "http://schema.org/",
  "@id": "#mark",
  "name": "mark",
  "gender": "male",
  "wife": {
    "@id": "#amber",
    "name": "amber",
    "gender": "female"
  },
  "self": {
    "@id": "#mark",
    "@type": "@id"
  }
}

mark was PUT { '@context': 'http://schema.org/',
  '@id': '#mark',
  name: 'mark',
  gender: 'male',
  wife: { '@id': '#amber', name: 'amber', gender: 'female' },
  self: { '@id': '#mark', '@type': '@id' } }

makeQuery #mark { '@context': 'http://schema.org/' }
GOT mark #mark null
save err Error: Not match for query: #mark in http://schema.org/

So how come I can PUT the above JSON into LevelGraph but there is no match when I try to query? What am I missing in my JsonLd to be valid for querying?

kristianmandrup commented 7 years ago

Hmm, when I console.log the get function I get this signature:

function (iri, context, options, callback) but in the docs I see this:

db.jsonld.get(manu['@id'], { '@context': manu['@context'] }, function(err, obj) {
  // obj will be the very same of the manu object
});

which has 3 arguments if I can count correctly?

BigBlueHat commented 7 years ago

Apparently, that JSON-LD isn't being stored when using db.jsonld.put()--despite it looking like it is being stored...

Try it out on the LevelGraph Playground. You can use db and jsonld in the console (as well as db.jsonld and db.n3).

What's weird is that if I turn this into N-Quads using the JSON-LD Playground, it does store just fine. However, the JSON-LD version (which is valid JSON-LD) does not store...

@jmatsushita any quick thoughts on this weirdness?

@kristianmandrup also, the options parameter is optional. :wink:

kristianmandrup commented 7 years ago

Thanks, I just looked into the code: index.js#L406 and I discovered what you just said about the optional options.

Will continue my exploration...

kristianmandrup commented 7 years ago

Now I get:

IO error: lock ./gundb/LOCK: already held by process

Can I just delete the ./gundb folder and start over? or do I need to shut down some process id? Could be the cause of my problems

jmatsushita commented 7 years ago

Hi there,

When debugging it's usful to see what LevelGraph directly returns (after putting with db.json.ld.put()) using : db.get({}, console.log);

In this case I think the problem is a missing "@base" in the context, or { base: "http://example.org } as an option on levelgraph-jsonld creation or passed with .put()

In other words, this works in the Playground:

{
  "@context": {
    "@vocab": "http://xmlns.com/foaf/0.1/",
    "@base": "http://example.org"
  },
  "@id": "mark",
  "name": "mark"
}

What happens behind the scenes (apart from not generating a useful error, which seems worth an issue) is that @id is not understood as a IRI. But that's not valid RDF. i.e. You can't say something about literals ("mark" is a string literal). Whereas "http://example.org/mark" is a resource and you can say things about it!

Cheers,

Jun

jmatsushita commented 7 years ago

The locking error is because levelup is not multi user by default. So indeed you must have another process with the db opened. As long as you don't have important data in it then deleting is an option. Killing zombie processes which might have the file locked is another (maybe best to take the habit of doing that instead of a delete...).

kristianmandrup commented 7 years ago

The minimal case I got working is this:

let mark = {
  "@context": "http://schema.org/",
  "@id": "http:#mark",
  "name": "mark"
}

The @id fields needs to be prefixed with http: or some protocol. Even h:#mark works, but not #mark on its own.

kristianmandrup commented 7 years ago

Even :mark worked, but it was much slower in my case. mark or #mark fails.

jmatsushita commented 7 years ago

In you case, open the db with a base option as described in the usage instructions. Note for instance that the JSON-LD Playground has a default 'base' setup automatically: http://json-ld.org/playground/#startTab=tab-expanded&json-ld=%7B%22%40context%22%3A%22http%3A%2F%2Fschema.org%2F%22%2C%22%40id%22%3A%22%23mark%22%2C%22name%22%3A%22mark%22%7D

I've opened an issue about better feedback and validation in this package.

BigBlueHat commented 7 years ago

@kristianmandrup :mark, http:mark, etc are all valid URI's (though they obviously wouldn't resolve to anything). #mark doesn't work because it's only a "fragment identifier" and not a complete URI. For instance, ?mark wouldn't work either because it's only a component of a full URI (the query string) and not an "absolute" URI.

The guiding principle here is known as the "open-world assumption" (OWA). Essentially, even "local" data identifiers need to be created in such a way that if they were to "surface" on the wider Web, they would not (ideally) conflict with anyone elses data. This is the reason that LevelGraph uses UUID-based blank nodes (_: prefixed UUIDs) rather than localized _:b1 (etc) style blank nodes.

LevelGraph does provide a way to set your own base URI (similar to how the JSON-LD Playground uses it's URI as the base). You can also do this per-PUT as @jmatsushita mentioned.

Ideally, though, your JSON-LD will already be using full URI's for @id values or will reference a @base URI within the JSON-LD (or within the @context you construct for your database or documents).

It can take a bit to shake the RDMS/"close world assumption" thinking, but the exchange is well worth it.

kristianmandrup commented 7 years ago

Thanks, I just tried different ids...

let mark = {
  "@context": "http://schema.org/",
  "@id": ":mark",
  "name": "mark",
}

let mark1 = {
  "@context": "http://www.schema.org",
  "@id": "person:mark",
  "name": "mark",
  "gender": "male",
  "wife": {
    "@id": "person:amber",
    "name": "amber",
    "gender": "female"
  }
}

let mark2 = {
  "@context": "http://www.schema.org",
  "@id": "http://www.schema.org/mark",
  "name": "mark",
  "gender": "male",
  "wife": {
    "@id": "http://www.schema.org/amber",
    "name": "amber",
    "gender": "female"
  }
}

Huge performance differences on GET. First one less than 1 sec. Next one around 2 secs. Last one seems to time out :O

I will look at the base option in the usage instructions. At least I kinda got it all working now :)

kristianmandrup commented 7 years ago

I'm using this as my default DB options

const jsonldOpts = {
  base: 'http://gun.io/base'
}

console.log('jsonld db', jsonldOpts) 
jsonld(lvGraphDb, jsonldOpts)

But still person#mark crashes while person:mark works. Anyways...

BigBlueHat commented 7 years ago

@kristianmandrup what do you mean by "crashes"?

The actual ID you'd be constructing with the @base + person#mark would be "http://gun.io/baseperson#mark`--it is indeed just string concatenation. Likely, that's not what you want.

Also, I'd not mint URI's under other people's domains (i.e. http://schema.org/mark). I know it's just play-testing at this point, but do try to use valid JSON-LD with some eye toward longevity--your testing will be more accurate and it will also help narrow the source of any bugs.

Lastly, the playgrounds are your friends! :smiley_cat: You can't go wrong by overusing them to test your JSON-LD before tossing it at the database:

Cheers!

kristianmandrup commented 7 years ago

All good :) I finally got the hang of it. First time I play for real with a semantic web DB since ages ago with RDF. Cheers! 😺

BigBlueHat commented 7 years ago

If you're happy with the result, would you mind closing this issue @kristianmandrup?

Thanks and have fun with LevelGraph!