fluree / core

Fluree releases and public bug reports
0 stars 0 forks source link

Inferencing based on `rdfs:subClassOf` fails if vocab inserted before data #82

Open Jackamus29 opened 5 months ago

Jackamus29 commented 5 months ago

Describe the bug If explicit rdfs:Class and rdfs:subClassOf definitions are transacted before any data of those types, queries that rely on inferencing do not work as expected.

To Reproduce

  1. Create with vocab data

    {
    "ledger": "inference-bug",
    "@context": {
    "rdfs": "http://www.w3.org/2000/01/rdf-schema#"
    },
    "insert": [
    {
      "@id": "Humanoid",
      "@type": "rdfs:Class"
    },
    {
      "@id": "Yeti",
      "@type": "rdfs:Class",
      "rdfs:subClassOf": {
        "@id": "Humanoid"
      }
    },
    {
      "@id": "Person",
      "@type": "rdfs:Class",
      "rdfs:subClassOf": {
        "@id": "Humanoid"
      }
    }
    ]
    }
  2. Insert Humanoids

    {
    "ledger": "inference-bug",
    "insert": [
    {
      "@id": "freddy",
      "@type": "Yeti",
      "name": "Freddy",
      "age": 4,
      "verified": true,
      "friends": [
        {
          "@id": "letty",
          "@type": "Yeti",
          "name": "Leticia",
          "nickname": "Letty",
          "age": 2
        },
        {
          "@id": "betty",
          "@type": "Yeti",
          "name": "Betty",
          "age": 82
        },
        {
          "@id": "andrew",
          "@type": "Person",
          "name": "Andrew",
          "age": 35
        }
      ]
    }
    ]
    }
  3. Query for Humanoids

    {
    "from": "inference-bug",
    "where": {
    "@id": "?s",
    "@type": "Humanoid"
    },
    "select": {
    "?s": [
      "*"
    ]
    }
    }

Expected behavior The query should return all subjects (Andrew and the Yetis)

Additional context This issue was reported by a community member via a GH Issue: https://github.com/fluree/db/issues/706

Andrew mentioned that the solve for this issue may be related to the solve for this issue: https://github.com/fluree/db/issues/599

aaj3f commented 5 months ago

For additional context, the crux of this issue is that if you introduce a class IRI overtly, e.g. by Fluree encountering the class like this for the first time:

    {
      "@id": "Yeti",
      "@type": "rdfs:Class",
       ...
     }

instead of Fluree encountering the class by doing this for the first time:

   {
     "@id": "ex:freddy",
     "@type": "Yeti",
     ...
   }

Then behavior like inferencing on rdfs:subClassOf will fail to work. I expect this is because Fluree reserves a particular lookup path for IRIs of vocab-like domain (e.g. properties, classes, etc), and when you introduce those IRIs by using them as values on @type or as property attributes in insertions, then they are recorded correctly. But if you introduce those IRIs explicitly by inserting an entity of type rdfs:Class then Fluree fails to handle them the way it would if I'd introduced it as the value of @type etc

JaceRockman commented 2 months ago

This appears to be working now. I'm running

(ns jace
  (:require [clojure.string :as str]
            [clojure.test :refer [deftest is testing]]
            [fluree.db.json-ld.api :as fluree]
            [fluree.db.test-utils :as test-utils]
            [fluree.db.util.core :as util]))

(def ledger-name "inference-bug-1")

(def init-data
  {"ledger" ledger-name,
   "insert" [{"createdAt" "Now"}]})

(def class-structure
  {"ledger"   ledger-name,
   "@context" {"rdfs" "http://www.w3.org/2000/01/rdf-schema#"},
   "insert"   [{"@id"   "Humanoid",
                "@type" "rdfs:Class"},
               {"@id"             "Yeti",
                "@type"           "rdfs:Class",
                "rdfs:subClassOf" {"@id" "Humanoid"}},
               {"@id"             "Person",
                "@type"           "rdfs:Class",
                "rdfs:subClassOf" {"@id" "Humanoid"}}]})

(def txn-data
  {"ledger" ledger-name,
   "insert" [{"@id"      "freddy",
              "@type"    "Yeti",
              "name"     "Freddy",
              "age"      4,
              "verified" true,
              "friends"  [{"@id"      "letty",
                           "@type"    "Yeti",
                           "name"     "Leticia",
                           "nickname" "Letty",
                           "age"      2},
                          {"@id"   "betty",
                           "@type" "Yeti",
                           "name"  "Betty",
                           "age"   82},
                          {"@id"   "andrew",
                           "@type" "Person",
                           "name"  "Andrew",
                           "age"   35}]}]})

(def query-humanoids
  {"@context" {"rdfs" "http://www.w3.org/2000/01/rdf-schema#"}
   :from   ledger-name,
   "where"  {"@id"   "?s",
             "@type" "Humanoid"},
   "select" {"?s" ["*"]}})

(def conn @(fluree/connect {:method :file
                            :storage-path "dev/data"}))

(def ledger @(fluree/create conn ledger-name))

(def db (-> ledger
            fluree/db
            (fluree/stage init-data)
            deref))

(def db-commit @(fluree/commit! ledger db))

(defn transact-entities
  []
  @(fluree/transact! conn txn-data)
  (println @(fluree/query-connection conn query-humanoids)))

(defn transact-classes
  []
  @(fluree/transact! conn class-structure)
  (println @(fluree/query-connection conn query-humanoids)))

  (transact-classes)
  (transact-entities)

which returns [{age 35, name Andrew, @type Person, @id andrew} {age 82, name Betty, @type Yeti, @id betty} {age 4, friends [{@id andrew} {@id betty} {@id letty}], name Freddy, verified true, @type Yeti, @id freddy} {age 2, name Leticia, nickname Letty, @type Yeti, @id letty}]