annotate utilities/composer/composer.cpp @ 53:bcea875d8d2f tip

More build fixes
author Chris Cannam
date Thu, 16 Oct 2014 19:03:51 +0100
parents add3570c6035
children
rev   line source
Chris@20 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@20 2
Chris@20 3 #include "Objects.h"
Chris@20 4 #include "TypeRegistrar.h"
Chris@20 5
Chris@20 6 #include <dataquay/BasicStore.h>
Chris@31 7 #include <dataquay/TransactionalStore.h>
Chris@20 8 #include <dataquay/RDFException.h>
Chris@28 9 #include <dataquay/objectmapper/ObjectLoader.h>
Chris@28 10 #include <dataquay/objectmapper/ObjectStorer.h>
Chris@31 11 #include <dataquay/objectmapper/ObjectMapper.h>
Chris@28 12 #include <dataquay/objectmapper/TypeMapping.h>
Chris@20 13
Chris@20 14 #include <QMultiMap>
Chris@20 15 #include <QFileInfo>
Chris@20 16
Chris@20 17 #include <iostream>
Chris@20 18
Chris@20 19 using namespace Dataquay;
Chris@20 20 using namespace ClassicalData;
Chris@20 21 using namespace std;
Chris@20 22
Chris@53 23 /*
Chris@20 24 ostream &operator<<(ostream &target, const QString &str)
Chris@20 25 {
Chris@20 26 return target << str.toLocal8Bit().data();
Chris@20 27 }
Chris@20 28
Chris@20 29 ostream &operator<<(ostream &target, const QUrl &u)
Chris@20 30 {
Chris@20 31 return target << "<" << u.toString() << ">";
Chris@20 32 }
Chris@53 33 */
Chris@20 34
Chris@20 35 bool
Chris@20 36 load(BasicStore *store, QString fileName)
Chris@20 37 {
Chris@20 38 QUrl url = QUrl::fromLocalFile(fileName);
Chris@20 39
Chris@20 40 cerr << "Importing from URL " << url << " ...";
Chris@20 41 try {
Chris@24 42 store->import(url, BasicStore::ImportPermitDuplicates);
Chris@20 43 } catch (RDFException e) {
Chris@24 44 cerr << " retrying with explicit ntriples type...";
Chris@24 45 try {
Chris@24 46 store->import(url, BasicStore::ImportPermitDuplicates, "ntriples");
Chris@24 47 } catch (RDFException e) {
Chris@24 48 cerr << "failed" << endl;
Chris@24 49 cerr << "Import failed: " << e.what() << endl;
Chris@24 50 return false;
Chris@24 51 }
Chris@20 52 }
Chris@20 53
Chris@20 54 cerr << " done" << endl;
Chris@20 55 return true;
Chris@20 56 }
Chris@20 57
Chris@20 58 void
Chris@20 59 usage(char *name)
Chris@20 60 {
Chris@20 61 int s = 0;
Chris@20 62 for (int i = 0; name[i]; ++i) if (name[i] == '/') s = i + 1;
Chris@20 63 name = name + s;
Chris@24 64 cerr << "Usage:" << endl;
Chris@24 65 cerr << " " << name << " <input-rdf-file> list" << endl;
Chris@24 66 cerr << " " << name << " <input-rdf-file> list-uris" << endl;
Chris@24 67 cerr << " " << name << " <input-rdf-file> show <uri> [<uri> ...]" << endl;
Chris@24 68 cerr << " " << name << " <input-rdf-file> search <text>" << endl;
Chris@24 69 cerr << " " << name << " <input-rdf-file> match <text>" << endl;
Chris@24 70 cerr << " " << name << " <input-rdf-file> merge <target-uri> <dup> [<dup> ...]" << endl;
Chris@42 71 cerr << " " << name << " <input-rdf-file> write" << endl;
Chris@20 72 exit(-1);
Chris@20 73 }
Chris@20 74
Chris@20 75 static QList<Composer *> allComposers;
Chris@20 76 static QMap<Composer *, QSet<Work *> > worksMap;
Chris@20 77
Chris@20 78 void
Chris@20 79 show(Composer *c)
Chris@20 80 {
Chris@20 81 cout << c->property("uri").value<Uri>() << endl;
Chris@20 82 cout << c->getSortName(true);
Chris@20 83 QString d = c->getDisplayDates();
Chris@20 84 if (d != "") cout << " (" << d << ")";
Chris@20 85 if (!c->nationality().empty() || c->period() != "") {
Chris@20 86 cout << " [";
Chris@20 87 bool first = true;
Chris@20 88 foreach (QString n, c->nationality()) {
Chris@20 89 if (!first) cout << "/";
Chris@20 90 cout << n;
Chris@20 91 first = false;
Chris@20 92 }
Chris@20 93 if (c->period() != "") {
Chris@20 94 if (!first) cout << ", ";
Chris@20 95 cout << c->period();
Chris@20 96 }
Chris@20 97 cout << "]";
Chris@20 98 }
Chris@20 99 if (c->gender() != "") {
Chris@20 100 cout << " *" << c->gender();
Chris@20 101 }
Chris@20 102 if (!worksMap[c].empty()) {
Chris@20 103 cout << " [" << worksMap[c].size() << " work(s)]";
Chris@20 104 }
Chris@20 105 cout << endl;
Chris@20 106 foreach (QString a, c->aliases()) {
Chris@20 107 cout << " - " << a << endl;
Chris@20 108 }
Chris@20 109 if (c->remarks() != "") {
Chris@20 110 cout << " " << c->remarks() << endl;
Chris@20 111 }
Chris@20 112 foreach (Document *d, c->pages()) {
Chris@24 113 cout << d->siteName() << " -> " << d->uri() << endl;
Chris@24 114 }
Chris@24 115 foreach (Uri u, c->otherURIs()) {
Chris@24 116 cout << "Same as " << u << endl;
Chris@20 117 }
Chris@20 118 }
Chris@20 119
Chris@20 120 void
Chris@20 121 showBrief(Composer *c)
Chris@20 122 {
Chris@20 123 cout << c->property("uri").value<Uri>() << endl;
Chris@20 124 cout << c->getSortName(false);
Chris@20 125 QString d = c->getDisplayDates();
Chris@20 126 if (d != "") cout << " (" << d << ")";
Chris@20 127 if (!c->nationality().empty() || c->period() != "") {
Chris@20 128 cout << " [";
Chris@20 129 bool first = true;
Chris@20 130 foreach (QString n, c->nationality()) {
Chris@20 131 if (!first) cout << "/";
Chris@20 132 cout << n;
Chris@20 133 first = false;
Chris@20 134 }
Chris@20 135 if (c->period() != "") {
Chris@20 136 if (!first) cout << " ";
Chris@20 137 cout << c->period();
Chris@20 138 }
Chris@20 139 cout << "]";
Chris@20 140 }
Chris@20 141 if (c->gender() != "") {
Chris@20 142 cout << " *" << c->gender();
Chris@20 143 }
Chris@20 144 if (!worksMap[c].empty()) {
Chris@20 145 cout << " [" << worksMap[c].size() << " work(s)]";
Chris@20 146 }
Chris@20 147 cout << endl;
Chris@20 148 }
Chris@20 149
Chris@20 150 void
Chris@20 151 listBrief(QList<Composer *> composers)
Chris@20 152 {
Chris@20 153 QMultiMap<QString, Composer *> sorted;
Chris@20 154 foreach (Composer *c, composers) {
Chris@20 155 sorted.insert(c->getSortName(false), c);
Chris@20 156 }
Chris@20 157 foreach (Composer *c, sorted) {
Chris@20 158 showBrief(c);
Chris@20 159 }
Chris@20 160 }
Chris@20 161
Chris@20 162 void
Chris@20 163 listUris(QList<Composer *> composers)
Chris@20 164 {
Chris@20 165 QMultiMap<Uri, Composer *> sorted;
Chris@20 166 foreach (Composer *c, composers) {
Chris@20 167 sorted.insert(c->property("uri").value<Uri>(), c);
Chris@20 168 }
Chris@20 169 foreach (Uri uri, sorted.keys()) {
Chris@20 170 cout << uri << endl;
Chris@20 171 }
Chris@20 172 }
Chris@20 173
Chris@20 174 void
Chris@20 175 showSearchResults(QMultiMap<float, Composer *> matches, int count)
Chris@20 176 {
Chris@20 177 int n = 0;
Chris@20 178 for (QMultiMap<float, Composer *>::const_iterator i = matches.end();
Chris@20 179 i != matches.begin(); ) {
Chris@20 180 --i;
Chris@20 181 if (i.key() <= 0) continue;
Chris@20 182 cout << endl;
Chris@20 183 if (n == 0) {
Chris@20 184 cout << "Best match:" << endl;
Chris@20 185 } else if (n == 1) {
Chris@20 186 cout << "Other candidate(s):" << endl;
Chris@20 187 }
Chris@20 188 cout << "[" << i.key() << "] ";
Chris@20 189 if (n == 0) show(i.value());
Chris@20 190 else showBrief(i.value());
Chris@20 191 if (++n > count) break;
Chris@20 192 }
Chris@20 193 if (n == 0) cout << "No matches" << endl;
Chris@20 194 cout << endl;
Chris@20 195 }
Chris@20 196
Chris@20 197 void
Chris@20 198 search(QString typing)
Chris@20 199 {
Chris@28 200 cout << "Searching (quick) for: " << typing << endl;
Chris@20 201 QMultiMap<float, Composer *> matches;
Chris@20 202 foreach (Composer *c, allComposers) {
Chris@28 203 float value = c->matchTypingQuick(typing);
Chris@28 204 matches.insert(value, c);
Chris@28 205 }
Chris@28 206 showSearchResults(matches, 5);
Chris@28 207
Chris@28 208 cout << "Searching (slow) for: " << typing << endl;
Chris@28 209 matches.clear();
Chris@28 210 foreach (Composer *c, allComposers) {
Chris@20 211 float value = c->matchTyping(typing);
Chris@20 212 matches.insert(value, c);
Chris@20 213 }
Chris@20 214 showSearchResults(matches, 5);
Chris@20 215 }
Chris@20 216
Chris@20 217 void
Chris@20 218 match(QString text)
Chris@20 219 {
Chris@20 220 cout << "Matching: " << text << endl;
Chris@20 221 QMultiMap<float, Composer *> matches;
Chris@20 222 QRegExp sre("[\\., -]+");
Chris@20 223 QStringList elements = text.toLower().split(sre, QString::SkipEmptyParts);
Chris@20 224 foreach (Composer *c, allComposers) {
Chris@20 225 float value = c->matchFuzzyName(elements);
Chris@20 226 matches.insert(value, c);
Chris@20 227 }
Chris@20 228 showSearchResults(matches, 5);
Chris@20 229 }
Chris@20 230
Chris@24 231 QList<Composer *>
Chris@24 232 matchWildcard(QString text)
Chris@24 233 {
Chris@24 234 if (!text.contains('/') && !text.contains('*')) {
Chris@24 235 text = "*" + text + "*";
Chris@24 236 }
Chris@24 237 QRegExp re(text, Qt::CaseInsensitive, QRegExp::Wildcard);
Chris@24 238 QList<Composer *> results;
Chris@24 239 foreach (Composer *c, allComposers) {
Chris@24 240 if (re.exactMatch(c->property("uri").value<Uri>().toString())) {
Chris@24 241 results.push_back(c);
Chris@24 242 }
Chris@24 243 }
Chris@24 244 return results;
Chris@24 245 }
Chris@24 246
Chris@24 247 Composer *
Chris@24 248 matchSingle(QString text)
Chris@24 249 {
Chris@24 250 QList<Composer *> matches = matchWildcard(text);
Chris@24 251 if (matches.empty()) {
Chris@24 252 cerr << "matchSingle: No matches for " << text << endl;
Chris@24 253 return 0;
Chris@24 254 } else if (matches.size() > 1) {
Chris@24 255 cerr << "matchSingle: Multiple matches for " << text << endl;
Chris@24 256 return 0;
Chris@24 257 }
Chris@24 258 return matches[0];
Chris@24 259 }
Chris@24 260
Chris@20 261 void
Chris@20 262 showWildcard(QString text)
Chris@20 263 {
Chris@20 264 cout << "Showing URI or wildcard: " << text << endl;
Chris@24 265 cout << endl;
Chris@24 266 foreach (Composer *c, matchWildcard(text)) {
Chris@24 267 show(c);
Chris@24 268 cout << endl;
Chris@20 269 }
Chris@24 270 }
Chris@24 271
Chris@24 272 void
Chris@26 273 merge(Composer *target, QList<Composer *> sources, BasicStore *store)
Chris@24 274 {
Chris@24 275 cout << "Merging into this composer record:" << endl << endl;
Chris@24 276 show(target);
Chris@24 277 cout << endl << "... the following composer record(s):" << endl;
Chris@24 278 foreach (Composer *c, sources) {
Chris@24 279 cout << endl;
Chris@24 280 show(c);
Chris@24 281 target->mergeFrom(c);
Chris@26 282
Chris@26 283 QSet<Work *> works = worksMap[c];
Chris@26 284 foreach (Work *w, works) {
Chris@26 285 w->composition()->setComposer(target);
Chris@26 286 }
Chris@26 287 worksMap[target].unite(works);
Chris@26 288 worksMap.remove(c);
Chris@26 289
Chris@26 290 delete c->birth();
Chris@26 291 delete c->death();
Chris@26 292 delete c;
Chris@26 293
Chris@26 294 //!!! and composition events!
Chris@24 295 }
Chris@24 296 cout << endl << "Result after merging:" << endl << endl;;
Chris@24 297 show(target);
Chris@20 298 cout << endl;
Chris@20 299 }
Chris@20 300
Chris@20 301 int
Chris@20 302 main(int argc, char **argv)
Chris@20 303 {
Chris@20 304 if (argc < 3) usage(argv[0]);
Chris@20 305 QString inFileName = argv[1];
Chris@20 306 QString command = argv[2];
Chris@20 307 QStringList args;
Chris@20 308 for (int i = 3; i < argc; ++i) {
Chris@20 309 args.push_back(argv[i]);
Chris@20 310 }
Chris@20 311
Chris@20 312 BasicStore *store = new BasicStore();
Chris@20 313 store->setBaseUri(Uri("http://dbtune.org/classical/resource/"));
Chris@28 314 ObjectLoader *loader = new ObjectLoader(store);
Chris@31 315 // loader->setFollowPolicy(ObjectLoader::FollowObjectProperties);
Chris@28 316
Chris@28 317 TypeMapping tm;
Chris@20 318
Chris@22 319 TypeRegistrar::registerTypes();
Chris@28 320 TypeRegistrar::addMappings(store, &tm);
Chris@28 321
Chris@28 322 loader->setTypeMapping(tm);
Chris@20 323
Chris@20 324 if (!load(store, inFileName)) {
Chris@20 325 cerr << "Failed to load data source" << endl;
Chris@20 326 return 1;
Chris@20 327 }
Chris@20 328
Chris@20 329 cerr << "Imported RDF data, mapping to objects...";
Chris@31 330 QObjectList objects = loader->loadAll();
Chris@20 331 cerr << " done" << endl;
Chris@20 332
Chris@28 333 delete loader;
Chris@20 334
Chris@42 335 bool write = false, writeFull = false;
Chris@31 336 if (command == "merge") {
Chris@31 337 write = true;
Chris@42 338 } else if (command == "write") {
Chris@42 339 writeFull = true;
Chris@31 340 }
Chris@20 341
Chris@31 342 TransactionalStore *ts = 0;
Chris@31 343 ObjectMapper *mapper = 0;
Chris@31 344
Chris@31 345 if (write) {
Chris@31 346 cerr << "Managing objects...";
Chris@31 347 ts = new TransactionalStore(store);
Chris@31 348 mapper = new ObjectMapper(ts);
Chris@31 349 mapper->setTypeMapping(tm);
Chris@31 350 mapper->manage(objects);
Chris@31 351 cerr << " done" << endl;
Chris@31 352 }
Chris@31 353
Chris@31 354 foreach (QObject *o, objects) {
Chris@31 355 Composer *c = qobject_cast<Composer *>(o);
Chris@31 356 if (c) allComposers.push_back(c);
Chris@31 357 }
Chris@31 358
Chris@31 359 QList<Work *> works;
Chris@31 360 foreach (QObject *o, objects) {
Chris@31 361 Work *w = qobject_cast<Work *>(o);
Chris@31 362 if (w) works.push_back(w);
Chris@31 363 }
Chris@31 364
Chris@20 365 foreach (Work *w, works) {
Chris@20 366 Composition *c = w->composition();
Chris@20 367 if (c) {
Chris@20 368 Composer *cp = c->composer();
Chris@20 369 if (cp) worksMap[cp].insert(w);
Chris@20 370 }
Chris@20 371 }
Chris@20 372
Chris@42 373 if (command == "write") {
Chris@42 374 if (!args.empty()) usage(argv[0]);
Chris@42 375 } else if (command == "list") {
Chris@22 376 if (!args.empty()) usage(argv[0]);
Chris@20 377 listBrief(allComposers);
Chris@20 378 } else if (command == "list-uris") {
Chris@22 379 if (!args.empty()) usage(argv[0]);
Chris@20 380 listUris(allComposers);
Chris@20 381 } else {
Chris@20 382 if (args.empty()) usage(argv[0]);
Chris@20 383 if (command == "show") {
Chris@20 384 foreach (QString s, args) {
Chris@20 385 showWildcard(s);
Chris@20 386 }
Chris@20 387 } else if (command == "search") {
Chris@20 388 foreach (QString s, args) {
Chris@20 389 search(s);
Chris@20 390 }
Chris@20 391 } else if (command == "match") {
Chris@20 392 foreach (QString s, args) {
Chris@20 393 match(s);
Chris@20 394 }
Chris@24 395 } else if (command == "merge") {
Chris@24 396 if (args.size() < 2) usage(argv[0]);
Chris@24 397 Composer *target = matchSingle(args[0]);
Chris@24 398 if (!target) return 1;
Chris@24 399 QList<Composer *> sources;
Chris@24 400 for (int i = 1; i < args.size(); ++i) {
Chris@24 401 Composer *c = matchSingle(args[i]);
Chris@24 402 if (!c) return 1;
Chris@24 403 sources.push_back(c);
Chris@24 404 }
Chris@26 405 merge(target, sources, store);
Chris@20 406 }
Chris@20 407 }
Chris@20 408
Chris@24 409 if (write) {
Chris@31 410
Chris@31 411 cerr << "Committing changes...";
Chris@31 412 mapper->commit();
Chris@24 413 cerr << " done" << endl;
Chris@24 414
Chris@24 415 cerr << "Saving to file out.ttl...";
Chris@25 416 store->save("out.ttl");
Chris@24 417 cerr << " done" << endl;
Chris@42 418
Chris@42 419 } else if (writeFull) {
Chris@42 420
Chris@42 421 ObjectStorer *storer = new ObjectStorer(store);
Chris@42 422
Chris@42 423 storer->setTypeMapping(tm);
Chris@42 424
Chris@42 425 storer->setPropertyStorePolicy(ObjectStorer::StoreIfChanged);
Chris@53 426 storer->setBlankNodePolicy(Dataquay::NeverUseBlankNodes);
Chris@42 427
Chris@42 428 cerr << "Mapping results back to store...";
Chris@42 429 storer->setFollowPolicy(ObjectStorer::FollowObjectProperties);
Chris@42 430 storer->store(objects);
Chris@42 431 cerr << " done" << endl;
Chris@42 432
Chris@42 433 cerr << "Saving to file out.ttl...";
Chris@42 434 store->save("out.ttl");
Chris@42 435 cerr << " done" << endl;
Chris@42 436
Chris@42 437 delete storer;
Chris@24 438 }
Chris@24 439
Chris@31 440 delete mapper;
Chris@31 441 delete ts;
Chris@31 442
Chris@25 443 delete store;
Chris@20 444 }
Chris@20 445