-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #99 from maartyman/add-optional
Added incremental optional operator
- Loading branch information
Showing
9 changed files
with
1,218 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
10 changes: 8 additions & 2 deletions
10
engines/config-query-sparql-incremental/config/rdf-join/actors-optional.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,16 @@ | ||
{ | ||
"@context": [ | ||
"https://linkedsoftwaredependencies.org/bundles/npm/@comunica/runner/^2.0.0/components/context.jsonld" | ||
"https://linkedsoftwaredependencies.org/bundles/npm/@comunica/runner/^2.0.0/components/context.jsonld", | ||
|
||
"https://linkedsoftwaredependencies.org/bundles/npm/@incremunica/actor-rdf-join-incremental-optional-hash/^1.0.0/components/context.jsonld" | ||
], | ||
"@id": "urn:comunica:default:Runner", | ||
"@type": "Runner", | ||
"actors": [ | ||
|
||
{ | ||
"@id": "urn:comunica:default:rdf-join/actors#incremental-optional-hash", | ||
"@type": "ActorRdfJoinIncrementalOptionalHash", | ||
"mediatorJoinSelectivity": { "@id": "urn:comunica:default:rdf-join-selectivity/mediators#main" } | ||
} | ||
] | ||
} |
Empty file.
31 changes: 31 additions & 0 deletions
31
packages/actor-rdf-join-incremental-optional-hash/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# Incremunica Incremental Optional Hash RDF Join Actor | ||
|
||
[![npm version](https://badge.fury.io/js/@incremunica%2Factor-rdf-join-incremental-optional-hash.svg)](https://badge.fury.io/js/@incremunica%2Factor-rdf-join-incremental-optional-hash) | ||
|
||
An Incremunica Optional Hash RDF Join Actor. | ||
|
||
## Install | ||
|
||
```bash | ||
$ yarn add @incremunica/actor-rdf-join-incremental-optional-hash | ||
``` | ||
|
||
## Configure | ||
|
||
After installing, this package can be added to your engine's configuration as follows: | ||
```text | ||
{ | ||
"@context": [ | ||
... | ||
"https://linkedsoftwaredependencies.org/bundles/npm/@incremunica/actor-rdf-join-incremental-optional-hash/^1.0.0/components/context.jsonld" | ||
], | ||
"actors": [ | ||
... | ||
{ | ||
"@id": "urn:comunica:default:rdf-join/actors#incremental-optional-hash", | ||
"@type": "ActorRdfJoinIncrementalOptionalHash", | ||
"mediatorJoinSelectivity": { "@id": "urn:comunica:default:rdf-join-selectivity/mediators#main" } | ||
} | ||
] | ||
} | ||
``` |
54 changes: 54 additions & 0 deletions
54
packages/actor-rdf-join-incremental-optional-hash/lib/ActorRdfJoinIncrementalOptionalHash.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import type { IActionRdfJoin, IActorRdfJoinArgs, IActorRdfJoinOutputInner } from '@comunica/bus-rdf-join'; | ||
import { ActorRdfJoin } from '@comunica/bus-rdf-join'; | ||
import type { IMediatorTypeJoinCoefficients } from '@comunica/mediatortype-join-coefficients'; | ||
import type { MetadataBindings } from '@comunica/types'; | ||
import type { BindingsStream } from '@incremunica/incremental-types'; | ||
import { IncrementalOptionalHash } from './IncrementalOptionalHash'; | ||
|
||
/** | ||
* An Incremunica Optional Hash RDF Join Actor. | ||
*/ | ||
export class ActorRdfJoinIncrementalOptionalHash extends ActorRdfJoin { | ||
public constructor(args: IActorRdfJoinArgs) { | ||
super(args, { | ||
logicalType: 'optional', | ||
physicalName: 'hash', | ||
limitEntries: 2, | ||
canHandleUndefs: false, | ||
}); | ||
} | ||
|
||
protected async getOutput(action: IActionRdfJoin): Promise<IActorRdfJoinOutputInner> { | ||
const metadatas = await ActorRdfJoin.getMetadatas(action.entries); | ||
const variables = ActorRdfJoin.overlappingVariables(metadatas); | ||
const join = new IncrementalOptionalHash( | ||
<BindingsStream><any>action.entries[0].output.bindingsStream, | ||
<BindingsStream><any>action.entries[1].output.bindingsStream, | ||
entry => ActorRdfJoinIncrementalOptionalHash.hash(entry, variables), | ||
<any> ActorRdfJoin.joinBindings, | ||
); | ||
return { | ||
result: { | ||
type: 'bindings', | ||
bindingsStream: join, | ||
metadata: async() => await this.constructResultMetadata( | ||
action.entries, | ||
await ActorRdfJoin.getMetadatas(action.entries), | ||
action.context, | ||
), | ||
}, | ||
}; | ||
} | ||
|
||
protected async getJoinCoefficients( | ||
action: IActionRdfJoin, | ||
metadatas: MetadataBindings[], | ||
): Promise<IMediatorTypeJoinCoefficients> { | ||
return { | ||
iterations: 0, | ||
persistedItems: 0, | ||
blockingItems: 0, | ||
requestTime: 0, | ||
}; | ||
} | ||
} |
160 changes: 160 additions & 0 deletions
160
packages/actor-rdf-join-incremental-optional-hash/lib/IncrementalOptionalHash.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
import type { Bindings as BindingsFactoryBindings } from '@incremunica/incremental-bindings-factory'; | ||
import { BindingsFactory } from '@incremunica/incremental-bindings-factory'; | ||
import { IncrementalInnerJoin } from '@incremunica/incremental-inner-join'; | ||
import type { Bindings, BindingsStream } from '@incremunica/incremental-types'; | ||
|
||
export class IncrementalOptionalHash extends IncrementalInnerJoin { | ||
private readonly rightMemory: Map<string, Bindings[]> = new Map<string, Bindings[]>(); | ||
private readonly leftMemory: Map<string, Bindings[]> = new Map<string, Bindings[]>(); | ||
private activeElement: Bindings | null = null; | ||
private otherArray: Bindings[] = []; | ||
private index = 0; | ||
private readonly funHash: (entry: Bindings) => string; | ||
private prependArray: boolean; | ||
private appendArray: boolean; | ||
private readonly bindingsFactory = new BindingsFactory(); | ||
|
||
public constructor( | ||
left: BindingsStream, | ||
right: BindingsStream, | ||
funHash: (entry: Bindings) => string, | ||
funJoin: (...bindings: Bindings[]) => Bindings | null, | ||
) { | ||
super(left, right, funJoin); | ||
this.funHash = funHash; | ||
} | ||
|
||
protected _cleanup(): void { | ||
this.leftMemory.clear(); | ||
this.rightMemory.clear(); | ||
this.activeElement = null; | ||
} | ||
|
||
protected hasResults(): boolean { | ||
return !this.leftIterator.done || | ||
!this.rightIterator.done || | ||
this.activeElement !== null; | ||
} | ||
|
||
private addOrDeleteFromMemory(item: Bindings, hash: string, memory: Map<string, Bindings[]>): boolean { | ||
let array = memory.get(hash); | ||
if (item.diff) { | ||
if (array === undefined) { | ||
array = []; | ||
memory.set(hash, array); | ||
} | ||
array.push(item); | ||
return true; | ||
} | ||
|
||
if (array === undefined) { | ||
return false; | ||
} | ||
|
||
if (array.length < 2 && array[0].equals(item)) { | ||
memory.delete(hash); | ||
return true; | ||
} | ||
|
||
const index = array.findIndex((bindings: Bindings) => item.equals(bindings)); | ||
if (index !== -1) { | ||
array[index] = array[array.length - 1]; | ||
array.pop(); | ||
return true; | ||
} | ||
return false; | ||
} | ||
|
||
public read(): Bindings | null { | ||
// eslint-disable-next-line no-constant-condition | ||
while (true) { | ||
if (this.ended) { | ||
return null; | ||
} | ||
|
||
// There is an active element | ||
if (this.activeElement !== null || this.appendArray) { | ||
if (this.index === this.otherArray.length) { | ||
if (this.prependArray) { | ||
this.prependArray = false; | ||
this.index = 0; | ||
continue; | ||
} | ||
if (this.appendArray && this.activeElement !== null) { | ||
this.index = 0; | ||
this.activeElement = null; | ||
continue; | ||
} | ||
this.appendArray = false; | ||
this.index = 0; | ||
this.activeElement = null; | ||
continue; | ||
} | ||
|
||
let resultingBindings = null; | ||
if (this.prependArray) { | ||
// We need to delete the bindings with no optional bindings | ||
resultingBindings = this.bindingsFactory.fromBindings(<BindingsFactoryBindings> this.otherArray[this.index]); | ||
resultingBindings.diff = false; | ||
} else if (this.activeElement === null) { | ||
// If this.activeElement is null, then appendArray is true | ||
// we need to add the bindings with no optional bindings | ||
resultingBindings = this.bindingsFactory.fromBindings(<BindingsFactoryBindings> this.otherArray[this.index]); | ||
resultingBindings.diff = true; | ||
} else { | ||
// Otherwise merge bindings | ||
resultingBindings = this.funJoin(this.activeElement, this.otherArray[this.index]); | ||
} | ||
|
||
this.index++; | ||
|
||
if (resultingBindings !== null) { | ||
return resultingBindings; | ||
} | ||
continue; | ||
} | ||
|
||
if (!this.hasResults()) { | ||
this._end(); | ||
} | ||
|
||
let item = this.rightIterator.read(); | ||
if (item !== null) { | ||
const hash = this.funHash(item); | ||
const rightMemEl = this.rightMemory.get(hash); | ||
if (this.addOrDeleteFromMemory(item, hash, this.rightMemory)) { | ||
const otherArray = this.leftMemory.get(hash); | ||
if (otherArray !== undefined) { | ||
if (item.diff && (rightMemEl === undefined || rightMemEl.length === 0)) { | ||
this.prependArray = true; | ||
} | ||
if (!item.diff && this.rightMemory.get(hash)?.length === 1) { | ||
this.appendArray = true; | ||
} | ||
this.activeElement = item; | ||
this.otherArray = otherArray; | ||
} | ||
} | ||
continue; | ||
} | ||
|
||
item = this.leftIterator.read(); | ||
if (item !== null) { | ||
const hash = this.funHash(item); | ||
if (this.addOrDeleteFromMemory(item, hash, this.leftMemory)) { | ||
const otherArray = this.rightMemory.get(hash); | ||
if (otherArray !== undefined) { | ||
this.activeElement = item; | ||
this.otherArray = otherArray; | ||
} else { | ||
return item; | ||
} | ||
} | ||
continue; | ||
} | ||
|
||
this.readable = false; | ||
return null; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './ActorRdfJoinIncrementalOptionalHash'; |
47 changes: 47 additions & 0 deletions
47
packages/actor-rdf-join-incremental-optional-hash/package.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
{ | ||
"name": "@incremunica/actor-rdf-join-incremental-optional-hash", | ||
"version": "1.2.2", | ||
"description": "An incremental-optional-hash rdf-join actor", | ||
"lsd:module": true, | ||
"main": "lib/index.js", | ||
"typings": "lib/index", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/maartyman/incremunica.git", | ||
"directory": "packages/actor-rdf-join-incremental-optional-hash" | ||
}, | ||
"publishConfig": { | ||
"access": "public" | ||
}, | ||
"sideEffects": false, | ||
"keywords": [ | ||
"comunica", | ||
"actor", | ||
"rdf-join", | ||
"incremental-optional-hash" | ||
], | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/maartyman/incremunica/issues" | ||
}, | ||
"homepage": "https://maartyman.github.io/incremunica/", | ||
"files": [ | ||
"components", | ||
"lib/**/*.d.ts", | ||
"lib/**/*.js", | ||
"lib/**/*.js.map" | ||
], | ||
"dependencies": { | ||
"@comunica/bus-rdf-join": "^2.10.1", | ||
"@comunica/mediatortype-join-coefficients": "^2.10.0", | ||
"@comunica/types": "^2.10.0", | ||
"@incremunica/incremental-bindings-factory": "^1.2.2", | ||
"@incremunica/incremental-inner-join": "^1.2.2", | ||
"@incremunica/incremental-types": "^1.2.2" | ||
}, | ||
"scripts": { | ||
"build": "npm run build:ts && npm run build:components", | ||
"build:ts": "node \"../../node_modules/typescript/bin/tsc\"", | ||
"build:components": "componentsjs-generator" | ||
} | ||
} |
Oops, something went wrong.