comparison rdf/RDFTransformFactory.cpp @ 489:82ab61fa9223

* Reorganise our sparql queries on the basis that Redland must be available, not only optional. So for anything querying the pool of data about plugins, we use a single datastore and model which is initialised at the outset by PluginRDFIndexer and then queried directly; for anything that "reads from a file" (e.g. loading annotations) we query directly using Rasqal, going to the datastore when we need additional plugin-related information. This may improve performance, but mostly it simplifies the code and fixes a serious issue with RDF import in the previous versions (namely that multiple sequential RDF imports would end up sharing the same RDF data pool!)
author Chris Cannam
date Fri, 21 Nov 2008 16:12:29 +0000
parents 3ffce691c9bf
children 23945cdd7161
comparison
equal deleted inserted replaced
488:1c66e199e7d9 489:82ab61fa9223
45 std::vector<Transform> getTransforms(ProgressReporter *); 45 std::vector<Transform> getTransforms(ProgressReporter *);
46 46
47 protected: 47 protected:
48 QString m_urlString; 48 QString m_urlString;
49 QString m_errorString; 49 QString m_errorString;
50 bool setOutput(Transform &, QString, QString); 50 bool setOutput(Transform &, QString);
51 bool setParameters(Transform &, QString, QString); 51 bool setParameters(Transform &, QString);
52 }; 52 };
53 53
54 54
55 QString 55 QString
56 RDFTransformFactory::getKnownExtensions() 56 RDFTransformFactory::getKnownExtensions()
110 std::vector<Transform> 110 std::vector<Transform>
111 RDFTransformFactoryImpl::getTransforms(ProgressReporter *reporter) 111 RDFTransformFactoryImpl::getTransforms(ProgressReporter *reporter)
112 { 112 {
113 std::vector<Transform> transforms; 113 std::vector<Transform> transforms;
114 114
115 // We have to do this a very long way round, to work around
116 // rasqal's current inability to handle correctly more than one
117 // OPTIONAL graph in a query
118
119 const char *optionals[] = {
120 "output",
121 "program",
122 "step_size",
123 "block_size",
124 "window_type",
125 "sample_rate",
126 "start",
127 "duration"
128 };
129
130 std::map<QString, Transform> uriTransformMap; 115 std::map<QString, Transform> uriTransformMap;
131 116
132 QString queryTemplate = 117 QString query =
133 " PREFIX vamp: <http://purl.org/ontology/vamp/> " 118 " PREFIX vamp: <http://purl.org/ontology/vamp/> "
134 119
135 " SELECT ?transform ?plugin %1 " 120 " SELECT ?transform ?plugin "
136 121
137 " FROM <%2> " 122 " FROM <%2> "
138 123
139 " WHERE { " 124 " WHERE { "
140 " ?transform a vamp:Transform ; " 125 " ?transform a vamp:Transform ; "
141 " vamp:plugin ?plugin . " 126 " vamp:plugin ?plugin . "
142 " %3 "
143 " } "; 127 " } ";
144 128
145 SimpleSPARQLQuery transformsQuery 129 SimpleSPARQLQuery transformsQuery
146 (m_urlString, queryTemplate.arg("").arg(m_urlString).arg("")); 130 (SimpleSPARQLQuery::QueryFromSingleSource, query.arg(m_urlString));
147 131
148 SimpleSPARQLQuery::ResultList transformResults = transformsQuery.execute(); 132 SimpleSPARQLQuery::ResultList transformResults = transformsQuery.execute();
149 133
150 if (!transformsQuery.isOK()) { 134 if (!transformsQuery.isOK()) {
151 m_errorString = transformsQuery.getErrorString(); 135 m_errorString = transformsQuery.getErrorString();
154 138
155 if (transformResults.empty()) { 139 if (transformResults.empty()) {
156 cerr << "RDFTransformFactory: NOTE: No RDF/TTL transform descriptions found in document at <" << m_urlString.toStdString() << ">" << endl; 140 cerr << "RDFTransformFactory: NOTE: No RDF/TTL transform descriptions found in document at <" << m_urlString.toStdString() << ">" << endl;
157 return transforms; 141 return transforms;
158 } 142 }
143
144 // There are various queries we need to make that might include
145 // data from iether the transform RDF or the model accumulated
146 // from plugin descriptions. For example, the transform RDF may
147 // specify the output's true URI, or it might have a blank node or
148 // some other URI with the appropriate vamp:identifier included in
149 // the file. To cover both cases, we need to add the file itself
150 // into the model and always query the model using the transform
151 // URI rather than querying the file itself subsequently.
152
153 SimpleSPARQLQuery::addSourceToModel(m_urlString);
159 154
160 PluginRDFIndexer *indexer = PluginRDFIndexer::getInstance(); 155 PluginRDFIndexer *indexer = PluginRDFIndexer::getInstance();
161 156
162 for (int i = 0; i < transformResults.size(); ++i) { 157 for (int i = 0; i < transformResults.size(); ++i) {
163 158
173 << transformUri.toStdString() << ">, skipping this transform" 168 << transformUri.toStdString() << ">, skipping this transform"
174 << endl; 169 << endl;
175 continue; 170 continue;
176 } 171 }
177 172
178 QString pluginDescriptionURL =
179 indexer->getDescriptionURLForPluginId(pluginId);
180 if (pluginDescriptionURL == "") {
181 cerr << "RDFTransformFactory: WARNING: No RDF description available for plugin <"
182 << pluginUri.toStdString() << ">, skipping transform <"
183 << transformUri.toStdString() << ">" << endl;
184 continue;
185 }
186
187 Transform transform; 173 Transform transform;
188 transform.setPluginIdentifier(pluginId); 174 transform.setPluginIdentifier(pluginId);
189 175
190 if (!setOutput(transform, transformUri, pluginDescriptionURL)) { 176 if (!setOutput(transform, transformUri)) {
191 return transforms; 177 return transforms;
192 } 178 }
193 179
194 if (!setParameters(transform, transformUri, pluginDescriptionURL)) { 180 if (!setParameters(transform, transformUri)) {
195 return transforms; 181 return transforms;
196 } 182 }
197 183
198 uriTransformMap[transformUri] = transform; 184 uriTransformMap[transformUri] = transform;
199 } 185
200 186 // We have to do this a very long way round, to work around
201 for (int i = 0; i < sizeof(optionals)/sizeof(optionals[0]); ++i) { 187 // rasqal's current inability to handle correctly more than one
202 188 // OPTIONAL graph in a query
203 QString optional = optionals[i]; 189
204 190 static const char *optionals[] = {
205 SimpleSPARQLQuery query 191 "output",
206 (m_urlString, 192 "program",
207 queryTemplate 193 "step_size",
208 .arg(QString("?%1").arg(optional)) 194 "block_size",
209 .arg(m_urlString) 195 "window_type",
210 .arg(QString("?transform vamp:%1 ?%2") 196 "sample_rate",
211 .arg(optionals[i]).arg(optional))); 197 "start",
212 198 "duration"
213 SimpleSPARQLQuery::ResultList results = query.execute(); 199 };
214 200
215 if (!query.isOK()) { 201 for (int j = 0; j < sizeof(optionals)/sizeof(optionals[0]); ++j) {
216 m_errorString = query.getErrorString(); 202
217 return transforms; 203 QString optional = optionals[j];
218 } 204
219 205 QString queryTemplate =
220 if (results.empty()) continue; 206 " PREFIX vamp: <http://purl.org/ontology/vamp/> "
221 207
222 for (int j = 0; j < results.size(); ++j) { 208 " SELECT ?%1 "
223 209
224 QString transformUri = results[j]["transform"].value; 210 " WHERE { "
211 " <%2> vamp:%1 ?%1 "
212 " } ";
225 213
226 if (uriTransformMap.find(transformUri) == uriTransformMap.end()) { 214 SimpleSPARQLQuery query
227 cerr << "RDFTransformFactory: ERROR: Transform URI <" 215 (SimpleSPARQLQuery::QueryFromModel,
228 << transformUri.toStdString() << "> not found in internal map!" << endl; 216 queryTemplate.arg(optional).arg(transformUri));
229 continue; 217
218 SimpleSPARQLQuery::ResultList results = query.execute();
219
220 if (!query.isOK()) {
221 m_errorString = query.getErrorString();
222 return transforms;
230 } 223 }
231 224
232 Transform &transform = uriTransformMap[transformUri]; 225 if (results.empty()) continue;
233 const SimpleSPARQLQuery::Value &v = results[j][optional]; 226
234 227 for (int k = 0; k < results.size(); ++k) {
235 if (v.type == SimpleSPARQLQuery::LiteralValue) { 228
229 const SimpleSPARQLQuery::Value &v = results[k][optional];
230
231 if (v.type == SimpleSPARQLQuery::LiteralValue) {
236 232
237 if (optional == "program") { 233 if (optional == "program") {
238 transform.setProgram(v.value); 234 transform.setProgram(v.value);
239 } else if (optional == "step_size") { 235 } else if (optional == "step_size") {
240 transform.setStepSize(v.value.toUInt()); 236 transform.setStepSize(v.value.toUInt());
241 } else if (optional == "block_size") { 237 } else if (optional == "block_size") {
242 transform.setBlockSize(v.value.toUInt()); 238 transform.setBlockSize(v.value.toUInt());
243 } else if (optional == "window_type") { 239 } else if (optional == "window_type") {
244 cerr << "NOTE: can't handle window type yet (value is \"" 240 cerr << "NOTE: can't handle window type yet (value is \""
245 << v.value.toStdString() << "\")" << endl; 241 << v.value.toStdString() << "\")" << endl;
246 } else if (optional == "sample_rate") { 242 } else if (optional == "sample_rate") {
247 transform.setSampleRate(v.value.toFloat()); 243 transform.setSampleRate(v.value.toFloat());
248 } else if (optional == "start") { 244 } else if (optional == "start") {
249 transform.setStartTime 245 transform.setStartTime
250 (RealTime::fromXsdDuration(v.value.toStdString())); 246 (RealTime::fromXsdDuration(v.value.toStdString()));
251 } else if (optional == "duration") { 247 } else if (optional == "duration") {
252 transform.setDuration 248 transform.setDuration
253 (RealTime::fromXsdDuration(v.value.toStdString())); 249 (RealTime::fromXsdDuration(v.value.toStdString()));
254 } else { 250 } else {
255 cerr << "RDFTransformFactory: ERROR: Inconsistent optionals lists (unexpected optional \"" << optional.toStdString() << "\"" << endl; 251 cerr << "RDFTransformFactory: ERROR: Inconsistent optionals lists (unexpected optional \"" << optional.toStdString() << "\"" << endl;
252 }
256 } 253 }
257 } 254 }
258 } 255 }
259 }
260
261 for (std::map<QString, Transform>::iterator i = uriTransformMap.begin();
262 i != uriTransformMap.end(); ++i) {
263
264 Transform &transform = i->second;
265 256
266 cerr << "RDFTransformFactory: NOTE: Transform is: " << endl; 257 cerr << "RDFTransformFactory: NOTE: Transform is: " << endl;
267 cerr << transform.toXmlString().toStdString() << endl; 258 cerr << transform.toXmlString().toStdString() << endl;
268 259
269 transforms.push_back(transform); 260 transforms.push_back(transform);
272 return transforms; 263 return transforms;
273 } 264 }
274 265
275 bool 266 bool
276 RDFTransformFactoryImpl::setOutput(Transform &transform, 267 RDFTransformFactoryImpl::setOutput(Transform &transform,
277 QString transformUri, 268 QString transformUri)
278 QString pluginDescriptionURL) 269 {
279 { 270 SimpleSPARQLQuery::Value outputValue =
280 SimpleSPARQLQuery outputQuery 271 SimpleSPARQLQuery::singleResultQuery
281 (m_urlString, 272 (SimpleSPARQLQuery::QueryFromModel,
282 QString 273 QString
283 ( 274 (
284 " PREFIX vamp: <http://purl.org/ontology/vamp/> " 275 " PREFIX vamp: <http://purl.org/ontology/vamp/> "
285 276
286 " SELECT ?output_id " 277 " SELECT ?output "
287 278
288 " FROM <%1> "
289 " FROM <%2> "
290
291 " WHERE { " 279 " WHERE { "
292 " <%3> vamp:output ?output . " 280 " <%1> vamp:output ?output . "
293 " ?output vamp:identifier ?output_id "
294 " } " 281 " } "
295 ) 282 )
296 .arg(m_urlString) 283 .arg(transformUri),
297 .arg(pluginDescriptionURL) 284 "output");
298 .arg(transformUri)); 285
299 286 if (outputValue.type == SimpleSPARQLQuery::NoValue) {
300 SimpleSPARQLQuery::ResultList outputResults = outputQuery.execute(); 287 return true;
301 288 }
302 if (!outputQuery.isOK()) { 289
303 m_errorString = outputQuery.getErrorString(); 290 if (outputValue.type != SimpleSPARQLQuery::URIValue) {
291 m_errorString = "No vamp:output given, or not a URI";
304 return false; 292 return false;
305 } 293 }
306 294
307 if (outputQuery.wasCancelled()) { 295 SimpleSPARQLQuery::Value outputIdValue =
308 m_errorString = "Query cancelled"; 296 SimpleSPARQLQuery::singleResultQuery
309 return false; 297 (SimpleSPARQLQuery::QueryFromModel,
310 }
311
312 for (int j = 0; j < outputResults.size(); ++j) {
313 QString outputId = outputResults[j]["output_id"].value;
314 transform.setOutput(outputId);
315 }
316
317 return true;
318 }
319
320
321 bool
322 RDFTransformFactoryImpl::setParameters(Transform &transform,
323 QString transformUri,
324 QString pluginDescriptionURL)
325 {
326 SimpleSPARQLQuery paramQuery
327 (m_urlString,
328 QString 298 QString
329 ( 299 (
330 " PREFIX vamp: <http://purl.org/ontology/vamp/> " 300 " PREFIX vamp: <http://purl.org/ontology/vamp/> "
331 301
302 " SELECT ?output_id "
303
304 " WHERE { "
305 " <%1> vamp:identifier ?output_id "
306 " } "
307 )
308 .arg(outputValue.value),
309 "output_id");
310
311 if (outputIdValue.type != SimpleSPARQLQuery::LiteralValue) {
312 m_errorString = "No output vamp:identifier available, or not a literal";
313 return false;
314 }
315
316 transform.setOutput(outputIdValue.value);
317
318 return true;
319 }
320
321
322 bool
323 RDFTransformFactoryImpl::setParameters(Transform &transform,
324 QString transformUri)
325 {
326 SimpleSPARQLQuery paramQuery
327 (SimpleSPARQLQuery::QueryFromModel,
328 QString
329 (
330 " PREFIX vamp: <http://purl.org/ontology/vamp/> "
331
332 " SELECT ?param_id ?param_value " 332 " SELECT ?param_id ?param_value "
333 333
334 " FROM <%1> "
335 " FROM <%2> "
336
337 " WHERE { " 334 " WHERE { "
338 " <%3> vamp:parameter_binding ?binding . " 335 " <%1> vamp:parameter_binding ?binding . "
339 " ?binding vamp:parameter ?param ; " 336 " ?binding vamp:parameter ?param ; "
340 " vamp:value ?param_value . " 337 " vamp:value ?param_value . "
341 " ?param vamp:identifier ?param_id " 338 " ?param vamp:identifier ?param_id "
342 " } " 339 " } "
343 ) 340 )
344 .arg(m_urlString)
345 .arg(pluginDescriptionURL)
346 .arg(transformUri)); 341 .arg(transformUri));
347 342
348 SimpleSPARQLQuery::ResultList paramResults = paramQuery.execute(); 343 SimpleSPARQLQuery::ResultList paramResults = paramQuery.execute();
349 344
350 if (!paramQuery.isOK()) { 345 if (!paramQuery.isOK()) {