@comunica/actor-rdf-join-entries-sort-traversal-zero-knowledge
Version:
A rdf-join-entries-sort actor that orders by increasing traversal-zero-knowledge
140 lines • 6.78 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ActorRdfJoinEntriesSortTraversalZeroKnowledge = void 0;
const bus_rdf_join_entries_sort_1 = require("@comunica/bus-rdf-join-entries-sort");
const context_entries_1 = require("@comunica/context-entries");
const core_1 = require("@comunica/core");
const rdf_terms_1 = require("rdf-terms");
const sparqlalgebrajs_1 = require("sparqlalgebrajs");
/**
* An actor that sorts join entries based on Hartig's heuristic for plan selection in link traversal environments.
*
* It first determines isolated connected graphs. (done by @comunica/actor-optimize-query-operation-join-connected)
* For each of the connected graphs, it orders triple patterns in BGPs by the following priority:
* 1. dependency-respecting: for each (non-first) pattern, at least one variable must occur in a preceding pattern.
* 2. seed: try to make the first pattern contain a source URI.
* 3. no vocab seed: avoid first triple pattern with vocab URI (variable predicate,
* or variable objects with rdf:type predicate)
* 4. filtering: patterns only containing variables also contained in preceding triple patterns
* are placed as soon as possible.
*
* It does this in an adaptive way.
* This means that this actor will only determine the first triple pattern,
* execute it, and materialize the remaining BGP based on its results.
* After that, the remaining BGP is evaluated recursively by this or another BGP actor.
*/
class ActorRdfJoinEntriesSortTraversalZeroKnowledge extends bus_rdf_join_entries_sort_1.ActorRdfJoinEntriesSort {
constructor(args) {
super(args);
}
/**
* Obtain all IRIs from the given pattern that are not related to vocabularies.
* Concretely, predicates will be omitted, and objects if predicate is http://www.w3.org/1999/02/22-rdf-syntax-ns#type
* @param pattern A quad pattern.
*/
static getPatternNonVocabUris(pattern) {
let nonVocabTerms;
const predicates = [];
if (pattern.type === 'pattern') {
predicates.push(pattern.predicate);
}
else {
sparqlalgebrajs_1.Util.recurseOperation(pattern, {
link(link) {
predicates.push(link.iri);
return false;
},
nps(nps) {
for (const iri of nps.iris) {
predicates.push(iri);
}
return false;
},
});
}
if (predicates
.some(predicate => predicate.termType === 'NamedNode' &&
predicate.value === 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type')) {
nonVocabTerms = [pattern.subject, pattern.graph];
}
else {
nonVocabTerms = [pattern.subject, pattern.object, pattern.graph];
}
return (0, rdf_terms_1.getNamedNodes)(nonVocabTerms);
}
/**
* Determine the source IRI of a given IRI without hash.
* @param namedNode An IRI.
*/
static getSourceUri(namedNode) {
const value = namedNode.value;
const hashPos = value.indexOf('#');
return hashPos > 0 ? value.slice(0, hashPos) : value;
}
/**
* Calculate a score for the given quad pattern based on a given set of sources.
* The more sources are present in the given pattern as non-vocab URIs, the higher the score.
* @param pattern A quad pattern.
* @param sources An array of sources.
*/
static getScoreSeedNonVocab(pattern, sources) {
return ActorRdfJoinEntriesSortTraversalZeroKnowledge.getPatternNonVocabUris(pattern)
.map(term => ActorRdfJoinEntriesSortTraversalZeroKnowledge.getSourceUri(term))
.filter(uri => sources.includes(uri))
.length;
}
/**
* Determine a score for the selectivity of the given pattern.
* The fewer variables, the higher the score.
* @param pattern A quad pattern.
*/
static getScoreSelectivity(pattern) {
const terms = pattern.type === 'pattern' ? (0, rdf_terms_1.getTerms)(pattern) : [pattern.subject, pattern.object, pattern.graph];
return rdf_terms_1.QUAD_TERM_NAMES.length - (0, rdf_terms_1.getVariables)(terms).length;
}
/**
* This sorts join entries by first prioritizing triple patterns in BGPs, and then all other operation types.
*
* Sort the patterns in BGPs by the following priorities:
* 1. A source in S or O (not O if rdf:type) (seed rule, no vocab rule)
* 2. Most selective: fewest variables (filtering rule, dependency-respecting rule)
* @param entries Quad patterns.
* @param sources The sources that are currently being queried.
*/
static sortJoinEntries(entries, sources) {
return [...entries].sort((entryA, entryB) => {
if ((entryA.operation.type === sparqlalgebrajs_1.Algebra.types.PATTERN || entryA.operation.type === sparqlalgebrajs_1.Algebra.types.PATH) &&
(entryB.operation.type === sparqlalgebrajs_1.Algebra.types.PATTERN || entryB.operation.type === sparqlalgebrajs_1.Algebra.types.PATH)) {
const compSeedNonVocab = ActorRdfJoinEntriesSortTraversalZeroKnowledge
.getScoreSeedNonVocab(entryB.operation, sources) -
ActorRdfJoinEntriesSortTraversalZeroKnowledge.getScoreSeedNonVocab(entryA.operation, sources);
if (compSeedNonVocab === 0) {
return ActorRdfJoinEntriesSortTraversalZeroKnowledge.getScoreSelectivity(entryB.operation) -
ActorRdfJoinEntriesSortTraversalZeroKnowledge.getScoreSelectivity(entryA.operation);
}
return compSeedNonVocab;
}
return entryA.operation.type === sparqlalgebrajs_1.Algebra.types.PATTERN ? -1 : 1;
});
}
async test(_action) {
return (0, core_1.passTestVoid)();
}
async run(action) {
// Determine all current sources
const sources = [];
const dataSources = action.context
.get(context_entries_1.KeysQueryOperation.querySources);
if (dataSources) {
for (const source of dataSources) {
const sourceValue = source.source.referenceValue;
if (typeof sourceValue === 'string') {
sources.push(sourceValue);
}
}
}
return { entries: ActorRdfJoinEntriesSortTraversalZeroKnowledge.sortJoinEntries(action.entries, sources) };
}
}
exports.ActorRdfJoinEntriesSortTraversalZeroKnowledge = ActorRdfJoinEntriesSortTraversalZeroKnowledge;
//# sourceMappingURL=ActorRdfJoinEntriesSortTraversalZeroKnowledge.js.map