radial sugiyama positioning integration
This commit is contained in:
@@ -3,6 +3,7 @@ package selection_queries
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
@@ -66,30 +67,83 @@ func selectedNodesFromIDs(idx Index, selectedIDs []uint32, includeBNodes bool) (
|
||||
return out, set
|
||||
}
|
||||
|
||||
func idsFromBindings(raw []byte, varName string, idx Index, selectedSet map[uint32]struct{}, includeBNodes bool) ([]uint32, error) {
|
||||
func idFromSparqlTerm(term sparqlTerm, idx Index, includeBNodes bool) (uint32, bool) {
|
||||
key, ok := termKeyFromSparqlTerm(term, includeBNodes)
|
||||
if !ok {
|
||||
return 0, false
|
||||
}
|
||||
nid, ok := idx.KeyToID[key]
|
||||
return nid, ok
|
||||
}
|
||||
|
||||
func tripleTermFromSparqlTerm(term sparqlTerm) TripleTerm {
|
||||
return TripleTerm{
|
||||
Type: term.Type,
|
||||
Value: term.Value,
|
||||
Lang: term.Lang,
|
||||
}
|
||||
}
|
||||
|
||||
func logQueryExecutionFailure(queryName string, selectedIDs []uint32, includeBNodes bool, sparql string, err error) {
|
||||
log.Printf(
|
||||
"%s: SPARQL execution failed selected_ids=%v include_bnodes=%t err=%v\nSPARQL:\n%s",
|
||||
queryName,
|
||||
selectedIDs,
|
||||
includeBNodes,
|
||||
err,
|
||||
strings.TrimSpace(sparql),
|
||||
)
|
||||
}
|
||||
|
||||
func resultFromTripleBindings(raw []byte, idx Index, selectedSet map[uint32]struct{}, includeBNodes bool) (Result, error) {
|
||||
var res sparqlResponse
|
||||
if err := json.Unmarshal(raw, &res); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse SPARQL JSON: %w", err)
|
||||
return Result{}, fmt.Errorf("failed to parse SPARQL JSON: %w", err)
|
||||
}
|
||||
|
||||
neighborSet := make(map[uint32]struct{})
|
||||
triples := make([]Triple, 0, len(res.Results.Bindings))
|
||||
for _, b := range res.Results.Bindings {
|
||||
term, ok := b[varName]
|
||||
if !ok {
|
||||
sTerm, okS := b["s"]
|
||||
pTerm, okP := b["p"]
|
||||
oTerm, okO := b["o"]
|
||||
if !okS || !okP || !okO {
|
||||
continue
|
||||
}
|
||||
key, ok := termKeyFromSparqlTerm(term, includeBNodes)
|
||||
if !ok {
|
||||
continue
|
||||
|
||||
triple := Triple{
|
||||
S: tripleTermFromSparqlTerm(sTerm),
|
||||
P: tripleTermFromSparqlTerm(pTerm),
|
||||
O: tripleTermFromSparqlTerm(oTerm),
|
||||
}
|
||||
nid, ok := idx.KeyToID[key]
|
||||
if !ok {
|
||||
continue
|
||||
|
||||
subjID, subjOK := idFromSparqlTerm(sTerm, idx, includeBNodes)
|
||||
if subjOK {
|
||||
id := subjID
|
||||
triple.SubjectID = &id
|
||||
}
|
||||
if _, sel := selectedSet[nid]; sel {
|
||||
continue
|
||||
objID, objOK := idFromSparqlTerm(oTerm, idx, includeBNodes)
|
||||
if objOK {
|
||||
id := objID
|
||||
triple.ObjectID = &id
|
||||
}
|
||||
neighborSet[nid] = struct{}{}
|
||||
if pTerm.Type == "uri" {
|
||||
if predID, ok := idx.PredicateIDByIRI[pTerm.Value]; ok {
|
||||
id := predID
|
||||
triple.PredicateID = &id
|
||||
}
|
||||
}
|
||||
|
||||
_, subjSelected := selectedSet[subjID]
|
||||
_, objSelected := selectedSet[objID]
|
||||
if subjOK && subjSelected && objOK && !objSelected {
|
||||
neighborSet[objID] = struct{}{}
|
||||
}
|
||||
if objOK && objSelected && subjOK && !subjSelected {
|
||||
neighborSet[subjID] = struct{}{}
|
||||
}
|
||||
|
||||
triples = append(triples, triple)
|
||||
}
|
||||
|
||||
ids := make([]uint32, 0, len(neighborSet))
|
||||
@@ -97,5 +151,5 @@ func idsFromBindings(raw []byte, varName string, idx Index, selectedSet map[uint
|
||||
ids = append(ids, nid)
|
||||
}
|
||||
sort.Slice(ids, func(i, j int) bool { return ids[i] < ids[j] })
|
||||
return ids, nil
|
||||
return Result{NeighborIDs: ids, Triples: triples}, nil
|
||||
}
|
||||
|
||||
@@ -17,12 +17,12 @@ func neighborsQuery(selectedNodes []NodeRef, includeBNodes bool) string {
|
||||
}
|
||||
|
||||
if len(valuesTerms) == 0 {
|
||||
return "SELECT ?nbr WHERE { FILTER(false) }"
|
||||
return "SELECT ?s ?p ?o WHERE { FILTER(false) }"
|
||||
}
|
||||
|
||||
bnodeFilter := ""
|
||||
if !includeBNodes {
|
||||
bnodeFilter = "FILTER(!isBlank(?nbr))"
|
||||
bnodeFilter = "FILTER(!isBlank(?s) && !isBlank(?o))"
|
||||
}
|
||||
|
||||
values := strings.Join(valuesTerms, " ")
|
||||
@@ -31,46 +31,55 @@ PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
|
||||
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
|
||||
PREFIX owl: <http://www.w3.org/2002/07/owl#>
|
||||
|
||||
SELECT DISTINCT ?nbr
|
||||
SELECT DISTINCT ?s ?p ?o
|
||||
WHERE {
|
||||
VALUES ?sel { %s }
|
||||
{
|
||||
?sel rdf:type ?o .
|
||||
VALUES ?sel { %s }
|
||||
BIND(?sel AS ?s)
|
||||
VALUES ?p { rdf:type }
|
||||
?s ?p ?o .
|
||||
?o rdf:type owl:Class .
|
||||
BIND(?o AS ?nbr)
|
||||
}
|
||||
UNION
|
||||
{
|
||||
?s rdf:type ?sel .
|
||||
VALUES ?sel { %s }
|
||||
VALUES ?p { rdf:type }
|
||||
?s ?p ?sel .
|
||||
?sel rdf:type owl:Class .
|
||||
BIND(?s AS ?nbr)
|
||||
BIND(?sel AS ?o)
|
||||
}
|
||||
UNION
|
||||
{
|
||||
?sel rdfs:subClassOf ?o .
|
||||
BIND(?o AS ?nbr)
|
||||
VALUES ?sel { %s }
|
||||
BIND(?sel AS ?s)
|
||||
VALUES ?p { rdfs:subClassOf }
|
||||
?s ?p ?o .
|
||||
}
|
||||
UNION
|
||||
{
|
||||
?s rdfs:subClassOf ?sel .
|
||||
BIND(?s AS ?nbr)
|
||||
VALUES ?sel { %s }
|
||||
VALUES ?p { rdfs:subClassOf }
|
||||
?s ?p ?sel .
|
||||
BIND(?sel AS ?o)
|
||||
}
|
||||
FILTER(!isLiteral(?nbr))
|
||||
FILTER(?nbr != ?sel)
|
||||
FILTER(!isLiteral(?o))
|
||||
FILTER(?s != ?o)
|
||||
%s
|
||||
}
|
||||
`, values, bnodeFilter)
|
||||
`, values, values, values, values, bnodeFilter)
|
||||
}
|
||||
|
||||
func runNeighbors(ctx context.Context, q Querier, idx Index, selectedIDs []uint32, includeBNodes bool) ([]uint32, error) {
|
||||
func runNeighbors(ctx context.Context, q Querier, idx Index, selectedIDs []uint32, includeBNodes bool) (Result, error) {
|
||||
selectedNodes, selectedSet := selectedNodesFromIDs(idx, selectedIDs, includeBNodes)
|
||||
if len(selectedNodes) == 0 {
|
||||
return []uint32{}, nil
|
||||
return Result{NeighborIDs: []uint32{}, Triples: []Triple{}}, nil
|
||||
}
|
||||
|
||||
raw, err := q.Query(ctx, neighborsQuery(selectedNodes, includeBNodes))
|
||||
query := neighborsQuery(selectedNodes, includeBNodes)
|
||||
raw, err := q.Query(ctx, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
logQueryExecutionFailure("neighbors", selectedIDs, includeBNodes, query, err)
|
||||
return Result{}, err
|
||||
}
|
||||
return idsFromBindings(raw, "nbr", idx, selectedSet, includeBNodes)
|
||||
return resultFromTripleBindings(raw, idx, selectedSet, includeBNodes)
|
||||
}
|
||||
|
||||
@@ -17,38 +17,42 @@ func subclassesQuery(selectedNodes []NodeRef, includeBNodes bool) string {
|
||||
}
|
||||
|
||||
if len(valuesTerms) == 0 {
|
||||
return "SELECT ?nbr WHERE { FILTER(false) }"
|
||||
return "SELECT ?s ?p ?o WHERE { FILTER(false) }"
|
||||
}
|
||||
|
||||
bnodeFilter := ""
|
||||
if !includeBNodes {
|
||||
bnodeFilter = "FILTER(!isBlank(?nbr))"
|
||||
bnodeFilter = "FILTER(!isBlank(?s) && !isBlank(?o))"
|
||||
}
|
||||
|
||||
values := strings.Join(valuesTerms, " ")
|
||||
return fmt.Sprintf(`
|
||||
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
|
||||
|
||||
SELECT DISTINCT ?nbr
|
||||
SELECT DISTINCT ?s ?p ?o
|
||||
WHERE {
|
||||
VALUES ?sel { %s }
|
||||
?nbr rdfs:subClassOf ?sel .
|
||||
FILTER(!isLiteral(?nbr))
|
||||
FILTER(?nbr != ?sel)
|
||||
VALUES ?p { rdfs:subClassOf }
|
||||
?s ?p ?sel .
|
||||
BIND(?sel AS ?o)
|
||||
FILTER(!isLiteral(?o))
|
||||
FILTER(?s != ?o)
|
||||
%s
|
||||
}
|
||||
`, values, bnodeFilter)
|
||||
}
|
||||
|
||||
func runSubclasses(ctx context.Context, q Querier, idx Index, selectedIDs []uint32, includeBNodes bool) ([]uint32, error) {
|
||||
func runSubclasses(ctx context.Context, q Querier, idx Index, selectedIDs []uint32, includeBNodes bool) (Result, error) {
|
||||
selectedNodes, selectedSet := selectedNodesFromIDs(idx, selectedIDs, includeBNodes)
|
||||
if len(selectedNodes) == 0 {
|
||||
return []uint32{}, nil
|
||||
return Result{NeighborIDs: []uint32{}, Triples: []Triple{}}, nil
|
||||
}
|
||||
|
||||
raw, err := q.Query(ctx, subclassesQuery(selectedNodes, includeBNodes))
|
||||
query := subclassesQuery(selectedNodes, includeBNodes)
|
||||
raw, err := q.Query(ctx, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
logQueryExecutionFailure("subclasses", selectedIDs, includeBNodes, query, err)
|
||||
return Result{}, err
|
||||
}
|
||||
return idsFromBindings(raw, "nbr", idx, selectedSet, includeBNodes)
|
||||
return resultFromTripleBindings(raw, idx, selectedSet, includeBNodes)
|
||||
}
|
||||
|
||||
@@ -17,38 +17,42 @@ func superclassesQuery(selectedNodes []NodeRef, includeBNodes bool) string {
|
||||
}
|
||||
|
||||
if len(valuesTerms) == 0 {
|
||||
return "SELECT ?nbr WHERE { FILTER(false) }"
|
||||
return "SELECT ?s ?p ?o WHERE { FILTER(false) }"
|
||||
}
|
||||
|
||||
bnodeFilter := ""
|
||||
if !includeBNodes {
|
||||
bnodeFilter = "FILTER(!isBlank(?nbr))"
|
||||
bnodeFilter = "FILTER(!isBlank(?s) && !isBlank(?o))"
|
||||
}
|
||||
|
||||
values := strings.Join(valuesTerms, " ")
|
||||
return fmt.Sprintf(`
|
||||
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
|
||||
|
||||
SELECT DISTINCT ?nbr
|
||||
SELECT DISTINCT ?s ?p ?o
|
||||
WHERE {
|
||||
VALUES ?sel { %s }
|
||||
?sel rdfs:subClassOf ?nbr .
|
||||
FILTER(!isLiteral(?nbr))
|
||||
FILTER(?nbr != ?sel)
|
||||
BIND(?sel AS ?s)
|
||||
VALUES ?p { rdfs:subClassOf }
|
||||
?s ?p ?o .
|
||||
FILTER(!isLiteral(?o))
|
||||
FILTER(?s != ?o)
|
||||
%s
|
||||
}
|
||||
`, values, bnodeFilter)
|
||||
}
|
||||
|
||||
func runSuperclasses(ctx context.Context, q Querier, idx Index, selectedIDs []uint32, includeBNodes bool) ([]uint32, error) {
|
||||
func runSuperclasses(ctx context.Context, q Querier, idx Index, selectedIDs []uint32, includeBNodes bool) (Result, error) {
|
||||
selectedNodes, selectedSet := selectedNodesFromIDs(idx, selectedIDs, includeBNodes)
|
||||
if len(selectedNodes) == 0 {
|
||||
return []uint32{}, nil
|
||||
return Result{NeighborIDs: []uint32{}, Triples: []Triple{}}, nil
|
||||
}
|
||||
|
||||
raw, err := q.Query(ctx, superclassesQuery(selectedNodes, includeBNodes))
|
||||
query := superclassesQuery(selectedNodes, includeBNodes)
|
||||
raw, err := q.Query(ctx, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
logQueryExecutionFailure("superclasses", selectedIDs, includeBNodes, query, err)
|
||||
return Result{}, err
|
||||
}
|
||||
return idsFromBindings(raw, "nbr", idx, selectedSet, includeBNodes)
|
||||
return resultFromTripleBindings(raw, idx, selectedSet, includeBNodes)
|
||||
}
|
||||
|
||||
@@ -13,8 +13,9 @@ type NodeRef struct {
|
||||
}
|
||||
|
||||
type Index struct {
|
||||
IDToNode map[uint32]NodeRef
|
||||
KeyToID map[string]uint32
|
||||
IDToNode map[uint32]NodeRef
|
||||
KeyToID map[string]uint32
|
||||
PredicateIDByIRI map[string]uint32
|
||||
}
|
||||
|
||||
type Meta struct {
|
||||
@@ -22,7 +23,27 @@ type Meta struct {
|
||||
Label string `json:"label"`
|
||||
}
|
||||
|
||||
type TripleTerm struct {
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value"`
|
||||
Lang string `json:"lang,omitempty"`
|
||||
}
|
||||
|
||||
type Triple struct {
|
||||
S TripleTerm `json:"s"`
|
||||
P TripleTerm `json:"p"`
|
||||
O TripleTerm `json:"o"`
|
||||
SubjectID *uint32 `json:"subject_id,omitempty"`
|
||||
ObjectID *uint32 `json:"object_id,omitempty"`
|
||||
PredicateID *uint32 `json:"predicate_id,omitempty"`
|
||||
}
|
||||
|
||||
type Result struct {
|
||||
NeighborIDs []uint32 `json:"neighbor_ids"`
|
||||
Triples []Triple `json:"triples"`
|
||||
}
|
||||
|
||||
type Definition struct {
|
||||
Meta Meta
|
||||
Run func(ctx context.Context, q Querier, idx Index, selectedIDs []uint32, includeBNodes bool) ([]uint32, error)
|
||||
Run func(ctx context.Context, q Querier, idx Index, selectedIDs []uint32, includeBNodes bool) (Result, error)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user