diff --git a/src/server/SparqlSearchEngine.js b/src/server/SparqlSearchEngine.js deleted file mode 100644 index a6e6f33cd430c2958d837f7cbd3a04f4bf168e18..0000000000000000000000000000000000000000 --- a/src/server/SparqlSearchEngine.js +++ /dev/null @@ -1,35 +0,0 @@ -import SparqlApi from './SparqlApi'; -import datasetConfig from './Datasets'; -import { - mapAllResults, - mergeAllResults -} from './Mappers'; -import { makeObjectList } from './SparqlObjectMapper'; - -class SparqlSearchEngine { - - doSearch(sparqlQuery, sparqlApi, mapper) { - return sparqlApi.selectQuery(sparqlQuery) - .then((data) => { - if (data.results.bindings.length === 0) { - return []; - } - // console.log(data.results.bindings) - return mapper ? mapper(data.results.bindings) : data.results.bindings; - }); - } - - getAllManuscripts(datasetId) { - const { endpoint, getAllQuery } = datasetConfig[datasetId]; - const sparqlApi = new SparqlApi({ endpoint }); - //console.log(getAllQuery) - return this.doSearch(getAllQuery, sparqlApi, makeObjectList); - } - - getFederatedManuscripts(datasets) { - return Promise.all(datasets.map((datasetId) => - this.getAllManuscripts(datasetId))).then(mergeAllResults); - } -} - -export default new SparqlSearchEngine(); diff --git a/src/server/index.js b/src/server/index.js index 9459bd2204ae2abecc6a7ed440f44652b5c7a2c7..e14fa2fc8fd2309205f0d1197fc0a65096435787 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -2,7 +2,7 @@ import express from 'express'; import bodyParser from 'body-parser'; import request from 'superagent'; import _ from 'lodash'; -import sparqlSearchEngine from './SparqlSearchEngine'; +import sparqlSearchEngine from './sparql/SparqlSearchEngine'; const DEFAULT_PORT = 3001; const app = express(); //const isDevelopment = app.get('env') !== 'production'; diff --git a/src/server/Datasets.js b/src/server/sparql/Datasets.js similarity index 78% rename from src/server/Datasets.js rename to src/server/sparql/Datasets.js index 29c1125e5c7ca33515d788f85d6210cbd657615a..ba46cbae5976c3ea4437f0cb89fc4783533ada75 100644 --- a/src/server/Datasets.js +++ b/src/server/sparql/Datasets.js @@ -6,7 +6,7 @@ module.exports = { 'timePeriod': '', //'endpoint': 'http://ldf.fi/mmm-sdbm-cidoc/sparql', 'endpoint': 'http://localhost:3034/ds/sparql', - 'getAllQuery': ` + 'allQuery': ` PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> PREFIX foaf: <http://xmlns.com/foaf/0.1/> @@ -20,12 +20,12 @@ module.exports = { PREFIX sdbm: <https://sdbm.library.upenn.edu/> SELECT ?id ?sdbm_id - (GROUP_CONCAT(DISTINCT ?label_id; SEPARATOR=", ") AS ?label) - (GROUP_CONCAT(DISTINCT ?author_id; SEPARATOR=", ") AS ?author) - (GROUP_CONCAT(DISTINCT ?timespan_id; SEPARATOR=", ") AS ?timespan) - (GROUP_CONCAT(DISTINCT ?creation_place_id; SEPARATOR=", ") AS ?creationPlace) - (GROUP_CONCAT(DISTINCT ?material_id; SEPARATOR=", ") AS ?material) - (GROUP_CONCAT(DISTINCT ?language_id; SEPARATOR=", ") AS ?language) + (GROUP_CONCAT(DISTINCT ?label_id; SEPARATOR=",") AS ?label) + (GROUP_CONCAT(DISTINCT ?author_id; SEPARATOR=",") AS ?author) + (GROUP_CONCAT(DISTINCT ?timespan_id; SEPARATOR=",") AS ?timespan) + (GROUP_CONCAT(DISTINCT ?creation_place_id; SEPARATOR=",") AS ?creationPlace) + (GROUP_CONCAT(DISTINCT ?material_id; SEPARATOR=",") AS ?material) + (GROUP_CONCAT(DISTINCT ?language_id; SEPARATOR=",") AS ?language) WHERE { ?id a frbroo:F4_Manifestation_Singleton . ?id rdfs:label ?label_id . @@ -42,6 +42,21 @@ module.exports = { } GROUP BY ?id ?sdbm_id `, + 'placeQuery': ` + PREFIX skos: <http://www.w3.org/2004/02/skos/core#> + PREFIX wgs84: <http://www.w3.org/2003/01/geo/wgs84_pos#> + PREFIX dc: <http://purl.org/dc/elements/1.1/> + SELECT DISTINCT ?id ?label ?lat ?long ?source + WHERE { + VALUES ?id { <ID> } + ?id skos:prefLabel ?label . + OPTIONAL { + ?id wgs84:lat ?lat ; + wgs84:long ?long . + } + OPTIONAL { ?id dc:source ?source . } + } + `, 'tgn': { // Getty LOD documentation: // http://vocab.getty.edu/queries#Places_by_Type diff --git a/src/server/Mappers.js b/src/server/sparql/Mappers.js similarity index 100% rename from src/server/Mappers.js rename to src/server/sparql/Mappers.js diff --git a/src/server/SparqlApi.js b/src/server/sparql/SparqlApi.js similarity index 100% rename from src/server/SparqlApi.js rename to src/server/sparql/SparqlApi.js diff --git a/src/server/SparqlObjectMapper.js b/src/server/sparql/SparqlObjectMapper.js similarity index 88% rename from src/server/SparqlObjectMapper.js rename to src/server/sparql/SparqlObjectMapper.js index c31f2f8ab44f80fd25013da09b9b3ac6298b021d..09f02ebdd361932d3e3128cf43473af0454c6f19 100644 --- a/src/server/SparqlObjectMapper.js +++ b/src/server/sparql/SparqlObjectMapper.js @@ -23,6 +23,10 @@ export const makeObjectList = (objects) => { //return self.postProcess(objList); }; +export const makeDict = (objects) => { + return arrayToObject(objects, 'id'); +}; + /** * @param {Object} obj A single SPARQL result row object. * @returns {Object} The mapped object. @@ -114,3 +118,15 @@ const merger = (a, b) => { } return mergeObjects(a, b); }; + +const arrayToObject = (array, keyField) => + array.reduce((obj, item) => { + let newItem = {}; + Object.entries(item).forEach(([key, value]) => { + if (key !== keyField) { + newItem[key] = value.value; + } + }); + obj[item[keyField].value] = newItem; + return obj; + }, {}); diff --git a/src/server/sparql/SparqlSearchEngine.js b/src/server/sparql/SparqlSearchEngine.js new file mode 100644 index 0000000000000000000000000000000000000000..6d94d9c341cb6555bb64acdbe282037e572968a4 --- /dev/null +++ b/src/server/sparql/SparqlSearchEngine.js @@ -0,0 +1,77 @@ +import _ from 'lodash'; +import SparqlApi from './SparqlApi'; +import datasetConfig from './Datasets'; +import { + //mapAllResults, + mergeAllResults +} from './Mappers'; +import { makeObjectList, makeDict } from './SparqlObjectMapper'; + +class SparqlSearchEngine { + + doSearch(sparqlQuery, endpoint, mapper) { + const sparqlApi = new SparqlApi({ endpoint }); + return sparqlApi.selectQuery(sparqlQuery) + .then((data) => { + if (data.results.bindings.length === 0) { + return []; + } + // console.log(data.results.bindings) + return mapper ? mapper(data.results.bindings) : data.results.bindings; + }); + } + + getAllManuscripts(datasetId) { + const { endpoint, allQuery } = datasetConfig[datasetId]; + return this.doSearch(allQuery, endpoint, makeObjectList); + } + + getFederatedManuscripts(datasets) { + return Promise.all(datasets.map((datasetId) => + this.getAllManuscripts(datasetId))) + .then(mergeAllResults) + .then((manuscripts) => this.getPlaces(manuscripts)); + } + + getPlaces(manuscripts) { + const { endpoint, placeQuery } = datasetConfig.mmm; + let placeIds = manuscripts.reduce((places, manuscript) => { + if (manuscript.creationPlace !== undefined) { + const creationPlaceArr = manuscript.creationPlace.split(','); + places = places.concat(creationPlaceArr); + } + return places; + }, []); + placeIds = Array.from(new Set(placeIds)); //remove duplicates + return this.doSearch(placeQuery.replace('<ID>', this.uriFy(placeIds)), endpoint, makeDict) + .then((placeDict) => { + manuscripts.map((manuscript) => { + if (manuscript.creationPlace !== undefined) { + let creationPlaceObjs; + const creationPlaceArr = manuscript.creationPlace.split(','); + if (creationPlaceArr.length > 1) { + creationPlaceObjs = creationPlaceArr.map((place) => { + return placeDict[place]; + }); + } else { + creationPlaceObjs = placeDict[creationPlaceArr[0]]; + } + manuscript.creationPlace = creationPlaceObjs; + return manuscript; + } + }); + return manuscripts; + }); + } + + uriFy(id) { + if (_.isArray(id)) { + return '<' + id.join('> <') + '>'; + } else if (id) { + return '<' + id + '>'; + } + return; + } +} + +export default new SparqlSearchEngine();