26 |
requested it. |
requested it. |
27 |
|
|
28 |
|
|
29 |
.. Issues |
Issues |
30 |
====== |
====== |
31 |
|
|
32 |
|
- Should we keep the current methods, and just add those |
33 |
|
proposed in this PEG? There is a lot of code using the |
34 |
|
current methods; we could just deprecate them for now. |
35 |
|
|
36 |
|
RESOLVED: No. The point is to *simplify* the API; |
37 |
|
adding more variants doesn't do that. |
38 |
|
|
39 |
|
Deprecating the current methods but not changing the code |
40 |
|
that uses them adds to the confusion, rather than making |
41 |
|
that code simpler. |
42 |
|
|
43 |
|
(I have volunteered to change the existing code |
44 |
|
if this PEG is accepted.) |
45 |
|
|
46 |
|
- What should happen in ``getObject()`` etc. |
47 |
|
if there is more than one triple of the requested form? |
48 |
|
|
49 |
|
RESOLVED: Do the same as currently: throw |
50 |
|
``NotUniqueException``. There are some problems |
51 |
|
associated with that (see mailing list discussions), |
52 |
|
but they are out of scope for this PEG. |
53 |
|
|
54 |
|
- What should be the name of the method returning |
55 |
|
a ``TripleIter``? ``get()``, for symmetry with |
56 |
|
the Collections API and the other functions; |
57 |
|
``find()``, similar to what we have now; or |
58 |
|
``query()`` for similarity with e.g. Aaron Swartz' |
59 |
|
Python API for RDF? |
60 |
|
|
61 |
|
RESOLVED: ``find()``. Tuomas explains: |
62 |
|
|
63 |
|
I feel better about ``find()``, since it |
64 |
|
|
65 |
|
1. feels lighter than query |
66 |
|
2. feels heavier than get, as it should - we don't *necessarily* |
67 |
|
have all indices ready. |
68 |
|
|
69 |
|
- Should you be able to query just subjects, i.e. ignoring objects, |
70 |
|
having them ``null`` in ``TripleIter`` and not getting duplicates? |
71 |
|
|
72 |
|
RESOLVED: No-- this is what ``getSubjects()`` etc. is for; |
73 |
|
working with a ``Set`` is more useful and consistent in these cases |
74 |
|
than working with a ``TriplesIter`` (and having one of its elements |
75 |
|
``null``, i.e. not really iterating through *triples*, etc.). |
76 |
|
|
77 |
|
|
78 |
A flavor of the API |
A flavor of the API |
79 |
=================== |
=================== |
82 |
through a set of triples. I propose the following |
through a set of triples. I propose the following |
83 |
interface:: |
interface:: |
84 |
|
|
85 |
for(Triples t = graph.get(_, RDF.type, _); t.loop();) { |
for(TripleIter i = graph.get(_, RDF.type, _); t.loop();) { |
86 |
System.out.println(t.sub+" is instance of "+t.ob); |
System.out.println(i.subj+" is instance of "+i.obj); |
87 |
} |
} |
88 |
|
|
89 |
I.e., have our own iterator-like thing, which iterates |
I.e., have our own iterator-like thing, which iterates |
105 |
when efficiency is at a premium. (Then again, when I print |
when efficiency is at a premium. (Then again, when I print |
106 |
to the console inside the loop, efficiency isn't at a |
to the console inside the loop, efficiency isn't at a |
107 |
premium anyway... but whatever...) The *fast* version |
premium anyway... but whatever...) The *fast* version |
108 |
would look like this:: |
would look like this [#speed]_:: |
109 |
|
|
110 |
for(Triples t = graph.get_A1A(RDF.type); t.loop()) { |
for(TripleIter t = graph.find_X1X(RDF.type); t.loop();) { |
111 |
System.out.println(t.sub+" is instance of "+t.ob); |
System.out.println(t.sub+" is instance of "+t.ob); |
112 |
} |
} |
113 |
|
|
116 |
|
|
117 |
In Jython, the loop would look like this:: |
In Jython, the loop would look like this:: |
118 |
|
|
119 |
t = graph.get(_, RDF.type, _) |
t = graph.find(_, RDF.type, _) |
120 |
|
|
121 |
while t.loop(): |
while t.loop(): |
122 |
print "<%s> is instance of <%s>" % (t.sub, t.ob) |
print "<%s> is instance of <%s>" % (t.sub, t.ob) |
130 |
We'll make it a convention that classes using the API |
We'll make it a convention that classes using the API |
131 |
have this at the top:: |
have this at the top:: |
132 |
|
|
133 |
static final _ = null; |
static final Object _ = null; |
134 |
|
|
135 |
You don't have to have this, but it makes things easier to read. |
You don't have to have this, but it makes things easier to read. |
136 |
|
|
138 |
``ConstGraph`` |
``ConstGraph`` |
139 |
-------------- |
-------------- |
140 |
|
|
141 |
``ConstGraph`` shall have the following API |
The current methods for finding triples shall be removed |
142 |
for getting triples:: |
from ``ConstGraph`` and be replaced by the following API:: |
143 |
|
|
144 |
/** Get an iterator through all triples in the graph |
/** Get an iterator through all triples in the graph |
145 |
* matching a certain pattern. |
* matching a certain pattern. |
148 |
* If any of the parameters is <code>null</code>, |
* If any of the parameters is <code>null</code>, |
149 |
* any node will match it. |
* any node will match it. |
150 |
*/ |
*/ |
151 |
Triples get(Object subject, Object predicate, Object object); |
TripleIter find(Object subject, Object predicate, Object object); |
152 |
|
|
153 |
// Versions that don't allow wildcards (``null``) |
// Versions that don't allow wildcards (``null``) |
154 |
Triples get_AA1(Object predicate, Object object); |
TripleIter find_XX1(Object predicate, Object object); |
155 |
Triples get_1A1(Object subject, Object object); |
TripleIter find_1X1(Object subject, Object object); |
156 |
... |
... |
157 |
|
|
158 |
/** Get the subject of the triple matching a certain pattern. |
/** Get the subject of the triple matching a certain pattern. |
162 |
* any node will match it. |
* any node will match it. |
163 |
* @returns The subject of the triple, if there is one, |
* @returns The subject of the triple, if there is one, |
164 |
* or <code>null</code> if there is no such triple. |
* or <code>null</code> if there is no such triple. |
165 |
|
* @throws NotUniqueException if there is more than one |
166 |
|
* matching triple in the graph. |
167 |
*/ |
*/ |
168 |
Object getSubject(Object subject, Object predicate, Object object); |
Object getSubject(Object subject, Object predicate, Object object) |
169 |
|
throws NotUniqueException; |
170 |
|
|
171 |
Object getSubject_A1A(Object predicate); |
Object getSubject_X1X(Object predicate) throws NotUniqueException; |
172 |
... |
... |
173 |
|
|
174 |
Note: The reason for having ``subject`` as a parameter |
Note: The reason for having ``subject`` as a parameter |
184 |
* If any of the parameters is <code>null</code>, |
* If any of the parameters is <code>null</code>, |
185 |
* any node will match it. |
* any node will match it. |
186 |
* <p> |
* <p> |
187 |
* The set is immutable; it is <em>not</em> backed |
* The set is backed by the graph (i.e., changing the graph |
188 |
* by the graph (i.e., changing the graph does not |
* changes the set, e.g. if the last triple with a given |
189 |
* change the set.) |
* subject is removed from the graph, that subject |
190 |
|
* disappears from the set). The set is <em>not</em> modifiable |
191 |
|
* (e.g. the <code>add()</code> and <code>remove()</code> methods |
192 |
|
* throw <code>UnsupportedOperationException</code>). |
193 |
*/ |
*/ |
194 |
Set getSubjects(Object subject, Object predicate, Object object); |
Set getSubjects(Object subject, Object predicate, Object object); |
195 |
|
|
196 |
(Backing is harder to program and I don't see the pay-off, |
Backing is generally used in the Collections API, and allows |
197 |
since the ``getXXXs`` functions won't be used that often.) |
for lighter implementations of the method. For example, |
198 |
|
when using ``new TreeSet(graph.getSubjects(_, _, _))`` to get |
199 |
|
a *sorted* set of all subjects in a graph, it would be quite |
200 |
|
wasteful if ``getSubjects()`` created a ``HashSet`` only to have |
201 |
|
it discarded after being used in the constructor of ``TreeSet``. |
202 |
|
|
203 |
Set getSubjects_AA1(Object object); |
Set getSubjects_XX1(Object object); |
204 |
... |
... |
205 |
|
|
206 |
// getObject(), getObjects() similarly |
// getObject(), getObjects() similarly |
207 |
// getPredicate(), getPredicates() similarly |
// getPredicates() similarly |
208 |
|
|
209 |
``getPredicate()`` is essentially useless, but we'll have it |
``getPredicate()`` is essentially useless, so we don't |
210 |
for symmetry. ``getPredicates()`` is useful, mostly for |
have it. This is symmetric with not having ``setPredicate()``, |
211 |
|
below. (If you need something to the same effect, |
212 |
|
you can use ``find()`` manually.) |
213 |
|
|
214 |
|
``getPredicates()`` is useful, mostly for |
215 |
getting *all* predicates used in a graph. |
getting *all* predicates used in a graph. |
216 |
|
|
217 |
Note that we don't have ``X`` in the function variants |
Note that we don't have ``A`` in the function variants |
218 |
any more, just ``1`` and ``A``, with ``A`` being equivalent |
any more, just ``1`` and ``X``, with ``X`` being equivalent |
219 |
to passing ``null`` in that position to the generic method. |
to passing ``null`` in that position to the generic method. |
220 |
|
|
221 |
(E.g., ``getSubjects_AAA()`` is equivalent to |
(E.g., ``getSubjects_XXX()`` is equivalent to |
222 |
``getSubjects(_, _, _)``, returning the set of all subjects |
``getSubjects(_, _, _)``, returning the set of all subjects |
223 |
in the graph.) |
in the graph.) |
224 |
|
|
225 |
|
|
226 |
``Triples`` |
``TripleIter`` |
227 |
----------- |
-------------- |
228 |
|
|
229 |
For the API of the iterator-like object, ``Triples``, |
For the API of the iterator-like object, ``TripleIter``, |
230 |
see ``swamp_easier_iteration--benja``. |
see ``swamp_easier_iteration--benja``. |
231 |
|
|
232 |
|
|
233 |
``Graph`` |
``Graph`` |
234 |
--------- |
--------- |
235 |
|
|
236 |
For changing graphs, the following API shall be used:: |
The current methods for adding, changing and removing triples |
237 |
|
shall be removed from ``Graph`` and replaced by:: |
238 |
|
|
239 |
/** Add a triple to this graph. */ |
/** Add a triple to this graph. */ |
240 |
void add(Object subject, Object predicate, Object object); |
void add(Object subject, Object predicate, Object object); |
247 |
*/ |
*/ |
248 |
void remove(Object subject, Object predicate, Object object); |
void remove(Object subject, Object predicate, Object object); |
249 |
|
|
250 |
void remove_A1A(Object predicate); |
void remove_X1X(Object predicate); |
251 |
void remove_1AA(Object subject); |
void remove_1XX(Object subject); |
252 |
... |
... |
253 |
|
|
254 |
/** Replace all triples with the given predicate and object |
/** Replace all triples with the given predicate and object |
280 |
I believe this API will be substantially simpler to use |
I believe this API will be substantially simpler to use |
281 |
than the one we have at the moment, and not lose |
than the one we have at the moment, and not lose |
282 |
anything w.r.t. speed. In fact, it may speed things up |
anything w.r.t. speed. In fact, it may speed things up |
283 |
in the future, because we can cache the ``Triples`` objects. |
in the future, because we can cache the ``TripleIter`` objects. |
284 |
|
|
285 |
|
\- Benja |
286 |
|
|
287 |
|
|
|
\- Benja |
|
288 |
|
.. [#speed] The speed difference between ``find(_, RDF.type, _)`` |
289 |
|
and ``find_X1X(RDF.type)`` is that ``find()`` has to check |
290 |
|
for ``null`` in each of the arguments (that's three ``jnz`` |
291 |
|
instructions) and do one method call. (If we can get the compiler |
292 |
|
to inline the ``find_XXX()`` variants, the method call goes away.) |
293 |
|
This may actually be fine even in an inner loop. (The |
294 |
|
hashtable lookups inside the loop will probably not be as cheap!) |
295 |
|
|
296 |
|
One might think that all fields of ``TripleIter`` |
297 |
|
(``subj``, ``pred``, ``obj``) need to be fetched for each |
298 |
|
iteration, but that's actually not true: Only those that are |
299 |
|
different from the previous iteration need to be fetched. |
300 |
|
(The implementation of the iterator can easily know |
301 |
|
which those are.) |
302 |
|
|
303 |
|
The only situation where this makes a speed difference |
304 |
|
is something like:: |
305 |
|
|
306 |
|
for(TripleIter i = graph.find(_, RDF.type, _); i.loop();) { |
307 |
|
System.out.println("Has an rdf:type: "+i.subj); |
308 |
|
} |
309 |
|
|
310 |
|
where fetching the ``obj`` each time is superfluous. |
311 |
|
This situation is not expected to be frequent enough |
312 |
|
to be a problem. |