Skip to content

# `` void

Functions:

- `generateVoID` –

  Returns a new graph with a VoID description of the passed dataset

## `` generateVoID

    generateVoID(g: Graph, dataset: Optional[IdentifiedNode] = None, res: Optional[Graph] = None, distinctForPartitions: bool = True)

Returns a new graph with a VoID description of the passed dataset

For more info on Vocabulary of Interlinked Datasets (VoID), see: http://vocab.deri.ie/void

This only makes two passes through the triples (once to detect the types of things)

The tradeoff is that lots of temporary structures are built up in memory meaning lots of memory may be consumed :) I imagine at least a few copies of your original graph.

the distinctForPartitions parameter controls whether distinctSubjects/objects are tracked for each class/propertyPartition this requires more memory again

Source code in `rdflib/void.py`

     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136

    def generateVoID(  # noqa: N802
        g: Graph,
        dataset: Optional[IdentifiedNode] = None,
        res: Optional[Graph] = None,
        distinctForPartitions: bool = True,  # noqa: N803
    ):
        """Returns a new graph with a VoID description of the passed dataset

        For more info on Vocabulary of Interlinked Datasets (VoID), see:
        http://vocab.deri.ie/void

        This only makes two passes through the triples (once to detect the types
        of things)

        The tradeoff is that lots of temporary structures are built up in memory
        meaning lots of memory may be consumed :)
        I imagine at least a few copies of your original graph.

        the distinctForPartitions parameter controls whether
        distinctSubjects/objects are tracked for each class/propertyPartition
        this requires more memory again
        """

        typeMap: Dict[_SubjectType, Set[_SubjectType]] = (  # noqa: N806
            collections.defaultdict(set)
        )
        classes: Dict[_ObjectType, Set[_SubjectType]] = collections.defaultdict(set)
        for e, c in g.subject_objects(RDF.type):
            classes[c].add(e)
            typeMap[e].add(c)

        triples = 0
        subjects: Set[_SubjectType] = set()
        objects: Set[_ObjectType] = set()
        properties: Set[_PredicateType] = set()
        classCount: DefaultDict[_SubjectType, int] = collections.defaultdict(  # noqa: N806
            int
        )
        propCount: DefaultDict[_PredicateType, int] = collections.defaultdict(  # noqa: N806
            int
        )

        classProps = collections.defaultdict(set)  # noqa: N806
        classObjects = collections.defaultdict(set)  # noqa: N806
        propSubjects = collections.defaultdict(set)  # noqa: N806
        propObjects = collections.defaultdict(set)  # noqa: N806

        for s, p, o in g:
            triples += 1
            subjects.add(s)
            properties.add(p)
            objects.add(o)

            # class partitions
            if s in typeMap:
                for c in typeMap[s]:
                    classCount[c] += 1
                    if distinctForPartitions:
                        classObjects[c].add(o)
                        classProps[c].add(p)

            # property partitions
            propCount[p] += 1
            if distinctForPartitions:
                propObjects[p].add(o)
                propSubjects[p].add(s)

        if not dataset:
            dataset = URIRef("http://example.org/Dataset")

        if not res:
            res = Graph()

        res.add((dataset, RDF.type, VOID.Dataset))

        # basic stats
        res.add((dataset, VOID.triples, Literal(triples)))
        res.add((dataset, VOID.classes, Literal(len(classes))))

        res.add((dataset, VOID.distinctObjects, Literal(len(objects))))
        res.add((dataset, VOID.distinctSubjects, Literal(len(subjects))))
        res.add((dataset, VOID.properties, Literal(len(properties))))

        for i, c in enumerate(classes):
            part = URIRef(dataset + "_class%d" % i)
            res.add((dataset, VOID.classPartition, part))
            res.add((part, RDF.type, VOID.Dataset))

            res.add((part, VOID.triples, Literal(classCount[c])))
            res.add((part, VOID.classes, Literal(1)))

            res.add((part, VOID["class"], c))

            res.add((part, VOID.entities, Literal(len(classes[c]))))
            res.add((part, VOID.distinctSubjects, Literal(len(classes[c]))))

            if distinctForPartitions:
                res.add((part, VOID.properties, Literal(len(classProps[c]))))
                res.add((part, VOID.distinctObjects, Literal(len(classObjects[c]))))

        for i, p in enumerate(properties):
            part = URIRef(dataset + "_property%d" % i)
            res.add((dataset, VOID.propertyPartition, part))
            res.add((part, RDF.type, VOID.Dataset))

            res.add((part, VOID.triples, Literal(propCount[p])))
            res.add((part, VOID.properties, Literal(1)))

            res.add((part, VOID.property, p))

            if distinctForPartitions:
                entities = 0
                propClasses = set()  # noqa: N806
                for s in propSubjects[p]:
                    if s in typeMap:
                        entities += 1
                    for c in typeMap[s]:
                        propClasses.add(c)

                res.add((part, VOID.entities, Literal(entities)))
                res.add((part, VOID.classes, Literal(len(propClasses))))

                res.add((part, VOID.distinctSubjects, Literal(len(propSubjects[p]))))
                res.add((part, VOID.distinctObjects, Literal(len(propObjects[p]))))

        return res, dataset