Coverage report: /development/source/library/org/datagraph/spocq-shard/src/store/rdfhdt/spocq-classes.lisp
| Kind | Covered | All | % |
| expression | 8 | 729 | 1.1 |
| branch | 0 | 48 | 0.0 |
Key
Not instrumented
Conditionalized out
Executed
Not executed
Both branches taken
One branch taken
Neither branch taken
1
;;; -*- Mode: lisp; Syntax: ansi-common-lisp; Base: 10; Package: org.datagraph.spocq.implementation; -*-
3
(in-package :org.datagraph.spocq.implementation)
5
(:documentation "SPOCQ rdfhdt extension"
6
"Specialize repository, revision and transaction classes
7
to refer to spocq wrappers for rdfhdt entities.
10
- hdt-repository : binds a reference to an hdt external record.
11
Open map the hdt context upon first use and close it when finalizing.
12
Treat the refernce as an opaque object - this is without access to its fields.
13
- hdt-revision : specialized in order to use an hdt-transaction.
14
- hdt-transaction : to conform to the standard access, but with no relation to
15
the state of the hdt map
21
The hdt map remains until the repository is terminated.
22
The hdt document components - header, dictionary triples, are treated as
23
opaque entities, just as the mapped context itself.
24
All operations are through operators
26
The lmdb practice is that an environment remain open for a process' duration.
27
On the other hand, each must be closed in order to release lmdb resources,
28
which are otherwise eventually exhausted. This occurs in terms of either
29
environments or databases at a relatively low limit.
30
The practice is also that a database be opened on the first occasion and then
31
remain open until the environment is closed. In order to effect this, the
32
respective transaction must be committed - even when it is read-only, while
33
the database remain open, after which the database is re-used in other
35
The practice with transactions is that they are created on-demand and must be
36
closed in order to release cursors - whereby cursors in a read-only
37
transaction must be closed explicitly.
39
This leads to the following pattern:
41
-> spocq:hdt-repository
42
-> rlmdb:repository : finalize closes environment
43
-> lmdb:environment : finalize closes lmdb entity iff still open
44
-> spocq:lmdb-revision
45
-> spocq:hdt-repository
46
-> rlmdb:repository : cloned from its referent repository
47
-> spocq:hdt-transaction : destroy transaction closes
50
This leads to two different processing patterns
54
the former arranges for the lmdb entity to have dynamic extent: the entity is
55
created/opened, as needed, upon entry and closed/destroyed upon exit iff it
57
the latter arranges for the entity to have indefinite extent: the entity is
58
created/opened, as needed, upon entry, but left intact upon exit.
60
this is reflected in individual operations as follows:
61
- autonomous operations use with-open-transaction.
62
this creates and manages a dynamic transaction for the cases where it should
63
be closed. eg. when opening the repository, the transaction must be closed in
64
order to afford the repository databases indefinite extent.
65
- retrieval operation use ensure-open-transaction with the single
66
lmdb:transaction bound into the spocq transaction.
67
this creates an lmdb entity with indefinite extent which is reused for all
68
get/put/cursor operations to cause all to use the same lmdb state.
70
access operations must support to modes:
71
- in the context of an hdt-repository, establish a dynamic transaction
72
wrt the lmdb environment for the databases to reuse. commit it at the
73
conclusion in order to leave them intact.
74
- in the context of an hdt-transaction, use its lmdb entity directly
75
for databases and leave it unchanged at the conclusion.
77
#+/-hdt-autonomous-transactions
78
if present supporess rdfcache transaction menagement for hdt
83
;;;(setq *class.repository* 'hdt-repository)
85
(defclass hdt-repository (lmdb-repository)
88
:reader get-repository-hdt-environment :writer setf-repository-hdt-environment
89
:documentation "binds a handle on an external hdt environment")
91
:initform 'hdt-transaction :allocation :class)
94
:initform 'hdt-repository-revision)
96
:initform 'hdt-document :allocation :class)
98
:accessor repository-term-count)
99
(spocq->store-term-registry
100
:reader repository-spocq->store-term-registry
101
:initform (make-registry :test #'equal)
102
:documentation "Maps native objects to their store identifiers in the context of the
103
query / repository. Terms cache the identifier internally.
104
It starts as a copy of the global registry and accumulates terms.")
105
(store->spocq-term-registry
106
:initform (make-registry :test #'equal)))
107
(:documentation "An HDT environment serves as a handle on a mapped rdfhdt file.
108
its constituents - header, dictionary, triples are made available via ffi
111
(defclass hdt-repository-revision (hdt-repository lmdb-revision)
113
(:documentation "Specialize the lmdb-revision for hdt datasets
114
This includes the temporal attributes in case they become relevant."))
116
(defclass hdt-document (rlmdb:repository) ;; (repository-storage)
117
;; use an lmdb database to map hdt term numbers to dydra term ordinals
118
;;!!! needs a different superclass in order to specify alternative databases
119
((rlmdb.i::transaction-class
120
:initform 'rlmdb:rdfcache-quad-transaction :allocation :class)))
122
(defgeneric repository-next-id (repository)
123
(:method ((repository hdt-repository))
124
;; not threadsafe !!!
125
;; use the graph role as it is unknown where it belongs
126
(hdt-box-term-number (incf (repository-term-count repository)) :graph)))
128
(defclass hdt-transaction (lmdb-transaction)
131
(defmethod validate-storage-class ((repository hdt-repository) (storage hdt-document))
134
(defgeneric (setf repository-hdt-environment) (%handle repository)
135
(:method (%handle (repository hdt-repository))
136
(let ((%old-handle (get-repository-hdt-environment repository)))
137
(when (and %old-handle (not (cffi:null-pointer-p %old-handle)))
138
(hdt:%delete-hdt %old-handle)
139
(sb-ext:cancel-finalization repository))
140
(when (and %handle (not (cffi:null-pointer-p %handle)))
141
(sb-ext:finalize repository
142
#'(lambda () (hdt:%delete-hdt %handle)))))
143
(setf-repository-hdt-environment %handle repository)))
145
(defgeneric repository-hdt-environment (repository)
146
(:method ((repository hdt-repository))
147
(or (get-repository-hdt-environment repository)
148
(let* ((file-pathname (repository-hdt-pathname repository)))
149
(unless (probe-file file-pathname)
150
(spocq.e:resource-not-found-error :resource (repository-uri repository)))
151
(let ((%handle (hdt:map-indexed-hdt file-pathname)))
152
(assert (and %handle (not (cffi:null-pointer-p %handle))) ()
153
"hdt open failed: ~s" (repository-pathname repository))
154
(setf (repository-term-count repository)
155
(+ (hdt::%hdt-get-n-subjects %handle)
156
(hdt::%hdt-get-n-properties %handle)
157
(hdt::%hdt-get-n-objects %handle)))
158
(setf (repository-hdt-environment repository) %handle)))))
159
(:method ((transaction hdt-transaction))
160
(repository-hdt-environment (transaction-repository transaction))))
162
(defparameter *hdt-filename* (make-pathname :name "dataset" :type "hdt"))
164
(defgeneric repository-hdt-pathname (repository)
165
(:method ((root pathname))
166
(merge-pathnames *hdt-filename* root))
167
(:method ((repository repository))
168
(repository-hdt-pathname (repository-catalog-pathname repository)))
169
(:method ((repository-id string))
170
(repository-hdt-pathname (repository-catalog-pathname repository-id))))
172
(defgeneric repository-is-hdt (designator)
173
(:method ((repository hdt-repository))
175
(:method ((object t))
177
(:method ((repository-id string))
178
(let ((id-type (repository-id-type repository-id)))
179
(if (and id-type (subtypep id-type *class.hdt-repository*))
181
(repository-is-hdt (repository-pathname repository-id)))))
182
(:method ((location pathname))
183
(probe-file (repository-hdt-pathname location))))
185
(pushnew (list *class.hdt-repository* (cl-ppcre:create-scanner "[^/]+/.+__hdt"))
186
*repository-id-type-map*
190
;!!! should be date-time
191
(defmethod repository-write-date ((repository hdt-repository))
192
"return the universal time for the last file modification"
193
(let ((pathname (repository-hdt-pathname repository)))
194
(when (probe-file pathname)
195
(let ((timestamp (file-write-date pathname)))
196
(universal-time-date-time timestamp)))))
198
(defmethod repository-revision-write-date ((repository hdt-repository) (revision-id string))
199
(repository-write-date repository))
201
(defmethod repository-write-timestamp ((repository hdt-repository))
202
"return the universal time for the last write"
203
(rlmdb:get-metadata-timestamp repository))
205
(defmethod initialize-repository-storage ((repository-id string) (prototype hdt-repository) &key)
207
(with-open-file (stream (repository-hdt-pathname repository-id)
208
:if-does-not-exist :create
212
;;; hdt transactions perform just the lmdb aspects
214
#+hdt-autonomous-transactions
215
(defmethod transaction-open ((transaction hdt-transaction) &key (if-does-not-exist :error))
216
(declare (ignore if-does-not-exist))
217
(when-transaction-record (%record transaction :error-p transaction-open)
218
(case (rdfcache::transaction-status %record)
219
((:initialized :uninitialized)
220
;; (rdfcache:print-transaction %record)
221
;; (rdfcache:begin-transaction %record)
222
(setf (rdfcache::transaction-status %record) :begun)
223
(trace-transaction 'transaction-open %record)
224
;; generate the uri proactively
225
(transaction-uri transaction)
226
(revision-uri transaction)
227
(log-debug "transaction-open: transaction: ~a" transaction)
229
((:begun :begin :mutated) t)
231
;; in any other state attempt to cancel the thread. this is observed when a compilation
232
;; step fails for one node, 'simultaneously' with others just starting out
233
;; if that returns, which means there is nothing prepared for this, signal an error
234
(log-warn "transaction-open: open a completed transaction: ~a" transaction)
235
(cancel-thread (bt:current-thread))
236
(error "transaction-open: no cancel-thread handler")))))
238
#+hdt-autonomous-transactions
239
(defmethod transaction-close ((transaction hdt-transaction) (disposition (eql :abort)))
240
(when-transaction-record (%record transaction)
241
(block :abort-transaction
242
;; try to handle these more delicately if the transaction is being closed
243
;; than in the standard exit-on-error case
244
(setf (rdfcache:transaction-status %record) :aborted))
245
;; no end time if aborted
246
;; !! no copy out any useful data and destroy it
247
;; !! make sure it is locked
248
(trace-transaction 'repository-close-transaction.abort %record)
249
(transaction-get-record-state transaction)))
250
#+hdt-autonomous-transactions
251
(defmethod transaction-close ((transaction hdt-transaction) (disposition (eql :commit))) ;;; (break "committing")
252
(when-transaction-record (%record transaction)
253
(case (rdfcache:transaction-status %record)
255
(setf (rdfcache:transaction-status %record) :committed)
256
(transaction-write-event transaction)))
257
(setf (transaction-end-time transaction) (get-universal-time))
258
(transaction-get-record-state transaction)
259
(trace-transaction 'transaction-close %record)))
260
#+hdt-autonomous-transactions
261
(defmethod transaction-close ((transaction hdt-transaction) (disposition (eql :abort)))
262
(let ((lmdb:transaction (bound-slot-value transaction 'lmdb-transaction)))
263
(when (lmdb:open-p lmdb:transaction)
264
(lmdb:abort-transaction lmdb:transaction))
265
(setf-transaction-lmdb-transaction nil transaction)))
266
#+hdt-autonomous-transactions
267
(defmethod transaction-close ((transaction hdt-transaction) (disposition (eql :commit)))
268
(let ((lmdb:transaction (bound-slot-value transaction 'lmdb-transaction)))
269
(when (lmdb:open-p lmdb:transaction)
270
(lmdb:commit-transaction lmdb:transaction))
271
(setf-transaction-lmdb-transaction nil transaction)))
274
(defmethod repository-wildcard-term ((repository hdt-repository))
277
(defmethod repository-wildcard-term-number ((repository hdt-repository))
280
(defmethod repository-wildcard-term-number ((transaction transaction))
281
(repository-wildcard-term-number (transaction-repository transaction)))
284
(defmethod repository-write-date ((revision hdt-repository-revision))
285
"return the universal time for the revision end timestamp"
286
(repository-write-date (repository-revision-reference revision)))
288
(defmethod repository-revision-write-date ((repository hdt-repository-revision) (revision-id string))
289
(repository-write-date (repository-revision-reference repository)))
291
(defmethod repository-revision-write-timestamp ((repository hdt-repository-revision) (revision-id string))
293
(repository-write-timestamp (repository-revision-reference repository)))
296
(defmethod transaction-write-event ((transaction hdt-transaction))
297
;; no write transactions are implemented
300
(defmethod repository-list-revision-ids ((repository hdt-repository))
303
(defmethod revisioned-repository-p ((repository hdt-repository))
306
(defmethod rlmdb:put-repository-metadata progn ((repository hdt-repository) &rest args)
307
;; uses it's associated lmdb repository to manage metadata
308
(apply #'rlmdb:put-repository-metadata (repository-lmdb-repository repository) args))
310
(defmethod repository-revision-bounds ((repository hdt-repository))
314
(defgeneric transaction-hdt-environment (transaction)
315
(:method ((transaction hdt-transaction))
316
(let* ((revision (transaction-revision transaction)))
317
(repository-hdt-environment revision))))
319
(defgeneric hdt-object-term-literal (object)
320
(:method ((object null))
322
(:method ((object symbol))
323
(assert (iri-p object))
324
(iri-lexical-form object))
325
(:method ((object spocq:iri))
326
(iri-lexical-form object))
327
(:method ((object t))
328
(let ((*expand-literal-values* t))
329
(with-output-to-string (stream) (encode-turtle-object object stream)))))
331
;; the cache can work in just the number->object direction as the number is
333
;; for hdt, the cache should be repository-relative as there are not revisions
334
(defgeneric hdt-object-term-number (repository object role)
335
(:documentation "lookup the role-specific term indentifier in the
336
hdt environment dictionary. a null argument yields zero, which is a wildcard.
337
if the term is not present, return nil")
338
(:method ((repository hdt-repository) object role)
340
(let* ((%environment (repository-hdt-environment repository))
341
(%dictionary (hdt:%hdt-get-dictionary %environment))
342
(term-literal (hdt-object-term-literal object)))
343
(hdt:%term-literal-term-number %dictionary term-literal role))
345
(:method ((transaction hdt-transaction) object role)
346
(hdt-object-term-number (transaction-repository transaction) object role)))
348
(defparameter *hdt-object-cache-mode* t)
350
(defgeneric hdt-term-number-object (repository term-number)
351
(:method ((repository hdt-repository) term-number)
352
(flet ((cache-object (object)
353
(when *hdt-object-cache-mode*
354
(setcache object (repository-spocq->store-term-registry repository) term-number)
355
(setcache term-number (repository-store->spocq-term-registry repository) object))
357
(if (= term-number 0)
358
(load-time-value (spocq:make-unbound-variable "0"))
359
(or (and *hdt-object-cache-mode*
360
(get-registry term-number (repository-store->spocq-term-registry repository)))
361
(let* ((%environment (repository-hdt-environment repository))
362
(%dictionary (hdt:%hdt-get-dictionary %environment))
363
(literal (hdt:%term-number-term-literal %dictionary term-number))
365
(if (plusp (length literal))
366
(case (char literal 0)
367
(#\" (parse-term literal))
368
(#\_ (intern-blank-node (subseq literal 2)))
369
(t (intern-iri literal)))
370
(spocq:make-unbound-variable (princ-to-string term-number)))))
371
(cache-object object))))))
372
(:method ((transaction hdt-transaction) term-number)
373
(hdt-term-number-object (transaction-repository transaction) term-number)))
375
(defmethod repository-term-number-object ((repository hdt-repository) term-number)
376
(hdt-term-number-object repository term-number))
377
(defmethod repository-term-number-object ((transaction hdt-transaction) term-number)
378
(repository-term-number-object (transaction-repository transaction) term-number))
380
(defmethod repository-object-term-number ((repository hdt-repository) object)
381
"Lookup the term identifier with the assumption that a query against an
382
hdt repository will abstract over the subject and object terms only and for that,
383
the shared subject id is sufficient.
384
if the terms is not found, make an ephemeral id and cache it
385
test cache first and cache always if the object is not in the dataset"
386
(or (get-registry object (repository-spocq->store-term-registry repository))
387
(hdt-object-term-number repository object :subject)
388
(let ((term-number (repository-next-id repository)))
389
(setf (get-registry object (repository-spocq->store-term-registry repository)) term-number)
390
(setf (get-registry term-number (repository-store->spocq-term-registry repository)) object)
393
(defmethod repository-object-term-number ((transaction hdt-transaction) object)
394
(repository-object-term-number (transaction-repository transaction) object))
397
(defgeneric hdt-intern-property-path (context property-path)
398
(:documentation "Intern a property path in a given transaction context. Descend to each verb in the path,
399
intern its term and cache the respective term number.")
401
(:method (context (path unary-property-path))
402
(hdt-intern-property-path context (unary-property-path-element path))
405
(:method (context (path nary-property-path))
406
(dolist (element (nary-property-path-elements path))
407
(hdt-intern-property-path context element))
410
(:method (context (path property-path-verb))
411
(or (property-path-verb-value path)
412
(setf (property-path-verb-value path)
413
(hdt-object-term-number context (property-path-verb-iri path) :predicate)))))
415
(defgeneric hdt-extern-field (solution-data)
416
(:documentation "Transform a term-number matrix/array into the object-solution field,
417
that is a list of solutions, based on the active hdt dictionary")
418
(:method ((solution-data array))
419
(let* ((field-length (array-dimension solution-data 0))
420
(field-width (array-dimension solution-data 1)))
421
(flet ((field-term-number-object (term-number)
422
(repository-term-number-object *repository* term-number)))
423
(loop for solution-index from 0 below field-length
424
collect (loop for term-index from 0 below field-width
425
collect (field-term-number-object (aref solution-data solution-index term-index)))))))
426
(:method ((term-number integer))
427
(repository-term-number-object *repository* term-number))
428
(:method ((datum t)) datum)
431
(:method ((matrix sb-sys:system-area-pointer))
432
(let ((numeric-field (rdfcache:matrix-to-list matrix)))
433
(hdt-extern-field (make-array (list (length numeric-field) (length (first numeric-field)))
434
:initial-contents numeric-field))))
436
(:method ((datum matrix-field))
437
(let ((solutions (solution-field-solutions datum)))
438
(unless (cffi:null-pointer-p solutions)
439
(let ((numeric-field (subseq (rdfcache:matrix-to-list solutions)
440
0 (solution-field-row-count datum))))
441
(hdt-extern-field (make-array (list (length numeric-field) (length (first numeric-field)))
442
:initial-contents numeric-field))))))
444
(:method ((generator solution-generator))
445
(let ((channel (abstract-field-generator-channel generator))
446
(dimensions (abstract-field-generator-dimensions generator))
448
(do-pages (page channel)
449
(push (term-value-field page) results))
450
(values (reduce #'nconc (nreverse results) :from-end t)
453
(defun test-sparql-hdt (query-string &rest args)
454
(apply #'test-sparql query-string
455
:solution-handler #'hdt-extern-field
458
;;; support for single-transaction describes
460
(defmethod process-describe ((subject-source hdt-transaction) (object-source hdt-transaction)
461
(destination array-page-channel)
462
(base-source array-page-channel)
463
base-dimensions subjects)
464
(let* ((repository (transaction-repository subject-source)))
465
(spocq.i::process-describe repository repository
466
destination base-source
467
base-dimensions subjects)))
469
(defmethod process-describe ((subject-source hdt-repository) (object-source hdt-repository)
470
(destination array-page-channel)
471
(base-source array-page-channel)
472
base-dimensions subjects)
474
(let* ((repository (transaction-repository subject-source)))
475
(spocq.i::process-describe repository repository
476
destination base-source
477
base-dimensions subjects)))
483
;;; kleen star path support
485
(defmethod map-repository-subject-and-objects ((continuation function) (transaction hdt-transaction) context &rest args)
486
(declare (ignore args)) ;; distinct is ignored
487
;; the path processsing does it anyway to merge subjects and object
488
;; function (context termid)
489
(let ((default-graph-term-number (repository-default-context-term-number transaction)))
490
(flet ((hdt-continuation (subject predicate object)
491
(declare (ignore predicate))
492
(funcall continuation default-graph-term-number subject)
493
(funcall continuation default-graph-term-number object)))
494
(declare (dynamic-extent #'hdt-continuation))
495
(let ((quad-pattern (vector context 0 0 0)))
496
(hdt:%map-repository-statements #'hdt-continuation (repository-hdt-environment transaction)
499
(defmethod repository-query-by-verb ((continuation t) (transaction hdt-transaction) context subject (predicate spocq:iri) object)
500
"if the predicate is an iri, use it as a term identifier."
501
(let ((id (hdt-object-term-number transaction predicate :predicate)))
503
(repository-query-by-verb continuation transaction context subject id object)
506
(defmethod repository-query-by-verb ((continuation t) (transaction hdt-transaction) context subject (predicate symbol) object)
507
"Iff a given symbol designates a term, then use the term's number as the predicate."
508
(let ((id (hdt-object-term-number transaction predicate :predicate)))
510
(repository-query-by-verb continuation transaction context subject id object))))
512
(defmethod repository-query-by-verb ((continuation t) (transaction hdt-transaction) context subject (predicate integer) object)
513
"if the predicate is an integer, it as a term number - perform the actual match and upon success
514
invoke the continuation with the concrete terms under cycle constraints"
515
(cond ((null (transaction-parent-p transaction))
516
(trace-paths "pp.rqbv.suppress : query-by-verb for empty repository: ~a" transaction)
519
(trace-paths "pp.rqbv.hdt : ~a(~a) ~a(~a) ~a(~a)~%"
520
(format-term-number-object subject) subject
521
(format-term-number-object predicate) predicate
522
(format-term-number-object object) object)
523
(let ((default-graph-term-number (repository-default-context-term-number transaction)))
524
(flet ((continue-with-statement (s p o)
525
(call-path-continuation continuation
526
(or *match-target-graph* context default-graph-term-number)
529
(declare (dynamic-extent #'continue-with-statement))
530
(hdt:%map-repository-statements* #'continue-with-statement (repository-hdt-environment transaction)
531
subject predicate object))))))
533
(defmethod repository-count-by-verb ((transaction hdt-transaction) context subject (predicate spocq:iri) object)
534
"if the predicate is an iri, use it as a term identifier."
535
(let ((id (hdt-object-term-number transaction predicate :predicate)))
537
(repository-count-by-verb transaction context subject id object)
540
(defmethod repository-count-by-verb ((transaction hdt-transaction) context subject (predicate symbol) object)
541
"Iff a given symbol designates a term, then use the term's number as the predicate. Otherwise return zero."
542
(let ((id (hdt-object-term-number transaction predicate :predicate)))
544
(repository-count-by-verb transaction context subject id object)
547
(defmethod repository-count-by-verb ((transaction hdt-transaction) context subject (predicate integer) object)
548
"Iff a given symbol designates a term, then use the term's number as the predicate. Otherwise return zero."
549
(hdt:%hdt-read-id-pattern-count (repository-hdt-environment transaction)
550
subject predicate object))
555
(defmethod repository-pattern-count ((repository hdt-repository) subject predicate object context)
556
(let ((wildcard-term "")) ;; (repository-wildcard-term repository)))
557
(flet ((hdt-term (term)
558
(if (or (null term) (and (spocq:blank-node-p term)) (variable-p term))
560
(hdt-object-term-literal term))))
561
(if (extension-operator-p predicate)
563
(let ((hdt-subject (hdt-term subject))
564
(hdt-predicate (hdt-term predicate))
565
(hdt-object (hdt-term object)))
566
(if (and (eql hdt-subject "") (eql hdt-predicate "") (eql hdt-object ""))
567
;; context does not matter in this relation
568
;; can delegate to a method which reads the count directly from the repo statistics record
569
(repository-statement-count repository)
570
(let ((stats (repository-statistics repository))
571
(pattern (list subject predicate object context)))
572
(declare (dynamic-extent pattern))
574
(or (gethash pattern stats)
575
(setf (get-registry (copy-list pattern) stats)
576
(hdt::%hdt-read-term-pattern-count (repository-hdt-environment repository)
577
hdt-subject hdt-predicate hdt-object))))))))))
579
(defmethod read-repository-statement-count ((repository hdt-repository))
580
(hdt:%hdt-statement-count (repository-hdt-environment repository)))
582
(defmethod read-repository-statement-count ((transaction hdt-transaction))
583
(read-repository-statement-count (transaction-repository transaction)))
589
(defmethod map-repository-contexts (function (transaction hdt-transaction) &rest args)
590
(declare (dynamic-extent args))
591
(apply #'map-repository-contexts function (transaction-repository transaction) args))
593
(defmethod map-repository-contexts (function (repository hdt-repository) &key distinct default)
594
"An hdt-repository comprises just one context, named as the instance identifier"
595
(declare (ignore distinct default))
596
;;;!!! claim the graph identifier is an object term
597
(funcall function (hdt-object-term-number repository (instance-identifier repository) :object)))
600
(defmethod map-repository-objects (function (transaction hdt-transaction) &rest args)
601
(declare (dynamic-extent args))
602
(apply #'map-repository-objects function (transaction-repository transaction) args))
604
(defmethod map-repository-objects (function (repository hdt-transaction) &key
605
context (distinct t))
606
(declare (dynamic-extent function))
607
(declare (ignore context))
608
(hdt::%map-object-numbers function (repository-hdt-environment repository)
611
(defmethod map-repository-predicates (function (transaction hdt-transaction) &rest args)
612
(declare (dynamic-extent args))
613
(apply #'map-repository-predicates function (transaction-repository transaction) args))
615
(defmethod map-repository-predicates (function (repository hdt-repository) &key
616
context (distinct t))
617
(declare (dynamic-extent function))
618
(declare (ignore context))
619
(hdt::%map-predicate-numbers function (repository-hdt-environment repository)
622
(defmethod map-repository-subjects (function (transaction hdt-transaction) &rest args)
623
(declare (dynamic-extent args))
624
(apply #'map-repository-subjects function (transaction-repository transaction) args))
626
(defmethod map-repository-subjects (function (repository hdt-repository) &key
627
context (distinct t))
628
(declare (dynamic-extent function))
629
(declare (ignore context))
630
(hdt::%map-subject-numbers function (repository-hdt-environment repository)
634
;;; term-level matching
636
(defmethod repository-match-field ((transaction hdt-transaction) context subject predicate object &rest args)
637
(declare (dynamic-extent args))
638
(apply #'repository-match-field (transaction-revision transaction) context subject predicate object args))
640
(defmethod repository-match-field ((revision hdt-repository-revision) context subject predicate object &rest args)
641
(declare (dynamic-extent args))
642
(apply #'repository-match-field (repository-revision-reference revision) context subject predicate object args))
644
(defmethod repository-match-field ((repository hdt-repository) context subject predicate object
645
&key (start 0) end dimensions (wild-blank-nodes-p t)
646
(first nil) (last nil))
647
"Generate a solution term sequence for the statements which match the argument term pattern.
648
Intern all terms. Should some term not be present, then return null.
649
Associate a (possible sparse) dimension list with the result to indicate which columns
651
The result field elements are ordered (c s p o).
652
For a single-file hdt repository, the graph is always the repository instance identifer.
654
The variant for hdt requires no transaction, as they are read-only."
655
(unless first (setf first (repository-last-revision repository)))
656
(unless last (setf last first))
657
(let* ((wildcard-term "") ;; (repository-wildcard-term repository))
661
(identifier (instance-identifier repository)))
663
(unless (equalp context identifier)
664
(log-warn "repository-match-field: context is ignored: ~s" context)))
665
(labels ((when-variable (term)
666
(when (variable-p term) term))
668
(if (or (null term) (and (spocq:blank-node-p term) wild-blank-nodes-p) (variable-p term))
670
(hdt-object-term-literal term)))
671
(spocq-term (hdt-term)
672
(parse-term hdt-term))
673
(collect-spo (subject predicate object)
674
;; returns quads although for the triple-htriple case the context
675
;; always indicates the default graph
676
(when (> (incf count) start)
677
(when (and end (> count end))
679
(push (list identifier
681
(spocq-term predicate)
685
(return-from repository-match-field (values (nreverse result) sort-dimensions first last))))
686
(declare (dynamic-extent #'collect-spo))
687
(setf sort-dimensions (remove nil (or dimensions
688
(list (when-variable context)
689
(when-variable subject)
690
(when-variable predicate)
691
(when-variable object)))))
692
(let ((hdt-subject (hdt-term subject))
693
(hdt-predicate (hdt-term predicate))
694
(hdt-object (hdt-term object)))
695
(hdt:%hdt-map-triple-strings* #'collect-spo (repository-hdt-environment repository)
703
(in-package :spocq.i)
705
(cffi:load-foreign-library #p"/opt/spocq/libhdt_lisp.so")
706
(load "patches/rdfhdt.lisp")
707
(load "patches/spocq-classes.lisp")
708
(load "patches/bgp-streaming.lisp")
710
(defparameter *allie-repo* (make-instance 'hdt-repository :id "hdtaccount/hdttest" :hdt-filename "allie_pubmed.hdt"))
711
(setf (repository "hdtaccount/hdttest") *allie-repo*)
712
(repository "hdtaccount/hdttest")
714
(trace hdt:%map-repository-statements* :break t hdt-continue-map compute-bgp-lambda)
715
(test-sparql "select count(*) where {?s ?p ?o}"
716
:repository-id "hdtaccount/hdttest")
718
(test-sparql "select (count(distinct ?p) as ?count) where {?s ?p ?o}"
719
:repository-id "hdtaccount/hdttest")
722
(test-sparql "select ?p (count (?p) as ?count)where {?s ?p ?o} group by ?p"
723
:repository-id "hdtaccount/hdttest")
725
((<http://example.org/subject20180323:398208461> 32275176)
726
(<http://example.org/subject20180323:407727994> 12439253)
727
(<http://example.org/object20180323:421498937> 10)
728
(<http://example.org/subject20180323:425791387> 18)
729
(<http://example.org/object20180323:425791387> 11) ("20180323:425791387" 4)
730
("20180323:421498937" 1) (<http://example.org/subject20180323:417175412> 3)
731
(<http://example.org/subject20180323:412499307> 24) ("20180323:412499307" 9)
732
(<http://example.org/object20180323:417175412> 18) ("20180323:407727994" 9)
733
(<http://example.org/object20180323:412499307> 9)
734
(<http://example.org/subject20180323:421498937> 2)
735
(<http://example.org/object20180323:398208461> 7647157)
736
(|http://www.w3.org/1999/02/22-rdf-syntax-ns#|:|type| 4792051)
737
("20180323:398208461" 3) (<http://example.org/subject20180323:402990116> 1)
738
(<http://example.org/object20180323:402990116> 1) ("20180323:402990116" 1)
739
(<http://example.org/object20180323:407727994> 2) ("20180323:417175412" 1)
740
(<http://example.org/subject20180323:430204034> 1))
742
(trace hdt::%id-cursor-next :break t)
744
(trace ORG.DATAGRAPH.SPOCQ.IMPLEMENTATION::OBJECT-TERM-NUMBER :break t
745
ORG.DATAGRAPH.SPOCQ.IMPLEMENTATION::RDFCACHE-FIND-OBJECT-TERM-NUMBER :break t
746
ORG.DATAGRAPH.SPOCQ.IMPLEMENTATION::RDFCACHE-LOOKUP-OBJECT-TERM-NUMBER :break t
747
ORG.DATAGRAPH.SPOCQ.IMPLEMENTATION::RDFCACHE-LOOKUP-OBJECT-TERM-NUMBER! :break t
748
ORG.DATAGRAPH.SPOCQ.IMPLEMENTATION::RDFCACHE-OBJECT-TERM-NUMBER :break t
749
ORG.DATAGRAPH.SPOCQ.IMPLEMENTATION::REPOSITORY-OBJECT-TERM-NUMBER :break t
751
;;; (defparameter *repo-name* "hdtaccount/hdttest")
752
;;; (repository-match-field *repo-name* nil nil nil nil)
753
;;; (time (dotimes (x 100) (repository-match-field *repo-name* nil nil nil nil))