comparison utilities/composer/composer.cpp @ 20:c4cb65c436ef classical-rdf

* Simple query utility
author Chris Cannam
date Tue, 23 Feb 2010 16:37:49 +0000
parents
children ea477e4cc75c
comparison
equal deleted inserted replaced
19:559a001e1bf5 20:c4cb65c436ef
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2
3 #include "Objects.h"
4 #include "TypeRegistrar.h"
5
6 #include <dataquay/BasicStore.h>
7 #include <dataquay/RDFException.h>
8 #include <dataquay/objectmapper/ObjectMapper.h>
9 #include <dataquay/Debug.h>
10
11 #include <QMultiMap>
12 #include <QFileInfo>
13
14 #include <iostream>
15
16 using namespace Dataquay;
17 using namespace ClassicalData;
18 using namespace std;
19
20 ostream &operator<<(ostream &target, const QString &str)
21 {
22 return target << str.toLocal8Bit().data();
23 }
24
25 ostream &operator<<(ostream &target, const QUrl &u)
26 {
27 return target << "<" << u.toString() << ">";
28 }
29
30
31 bool
32 load(BasicStore *store, QString fileName)
33 {
34 QUrl url = QUrl::fromLocalFile(fileName);
35
36 cerr << "Importing from URL " << url << " ...";
37 try {
38 store->import(url, BasicStore::ImportIgnoreDuplicates, "ntriples");
39 } catch (RDFException e) {
40 cerr << "failed" << endl;
41 cerr << "Import failed: " << e.what() << endl;
42 return false;
43 }
44
45 cerr << " done" << endl;
46 return true;
47 }
48
49 void
50 usage(char *name)
51 {
52 int s = 0;
53 for (int i = 0; name[i]; ++i) if (name[i] == '/') s = i + 1;
54 name = name + s;
55 cerr << "Usage: " << name << " <input-rdf-file> list" << endl;
56 cerr << "Usage: " << name << " <input-rdf-file> list-uris" << endl;
57 cerr << "Usage: " << name << " <input-rdf-file> show <uri> [<uri> ...]" << endl;
58 cerr << "Usage: " << name << " <input-rdf-file> search <text>" << endl;
59 cerr << "Usage: " << name << " <input-rdf-file> match <text>" << endl;
60 exit(-1);
61 }
62
63 static QList<Composer *> allComposers;
64 static QMap<Composer *, QSet<Work *> > worksMap;
65
66 void
67 show(Composer *c)
68 {
69 cout << c->property("uri").value<Uri>() << endl;
70 cout << c->getSortName(true);
71 QString d = c->getDisplayDates();
72 if (d != "") cout << " (" << d << ")";
73 if (!c->nationality().empty() || c->period() != "") {
74 cout << " [";
75 bool first = true;
76 foreach (QString n, c->nationality()) {
77 if (!first) cout << "/";
78 cout << n;
79 first = false;
80 }
81 if (c->period() != "") {
82 if (!first) cout << ", ";
83 cout << c->period();
84 }
85 cout << "]";
86 }
87 if (c->gender() != "") {
88 cout << " *" << c->gender();
89 }
90 if (!worksMap[c].empty()) {
91 cout << " [" << worksMap[c].size() << " work(s)]";
92 }
93 cout << endl;
94 foreach (QString a, c->aliases()) {
95 cout << " - " << a << endl;
96 }
97 if (c->remarks() != "") {
98 cout << " " << c->remarks() << endl;
99 }
100 foreach (Document *d, c->pages()) {
101 cout << " " << d->siteName() << " -> " << d->uri() << endl;
102 }
103 }
104
105 void
106 showBrief(Composer *c)
107 {
108 cout << c->property("uri").value<Uri>() << endl;
109 cout << c->getSortName(false);
110 QString d = c->getDisplayDates();
111 if (d != "") cout << " (" << d << ")";
112 if (!c->nationality().empty() || c->period() != "") {
113 cout << " [";
114 bool first = true;
115 foreach (QString n, c->nationality()) {
116 if (!first) cout << "/";
117 cout << n;
118 first = false;
119 }
120 if (c->period() != "") {
121 if (!first) cout << " ";
122 cout << c->period();
123 }
124 cout << "]";
125 }
126 if (c->gender() != "") {
127 cout << " *" << c->gender();
128 }
129 if (!worksMap[c].empty()) {
130 cout << " [" << worksMap[c].size() << " work(s)]";
131 }
132 cout << endl;
133 }
134
135 void
136 listBrief(QList<Composer *> composers)
137 {
138 QMultiMap<QString, Composer *> sorted;
139 foreach (Composer *c, composers) {
140 sorted.insert(c->getSortName(false), c);
141 }
142 foreach (Composer *c, sorted) {
143 showBrief(c);
144 }
145 }
146
147 void
148 listUris(QList<Composer *> composers)
149 {
150 QMultiMap<Uri, Composer *> sorted;
151 foreach (Composer *c, composers) {
152 sorted.insert(c->property("uri").value<Uri>(), c);
153 }
154 foreach (Uri uri, sorted.keys()) {
155 cout << uri << endl;
156 }
157 }
158
159 void
160 showSearchResults(QMultiMap<float, Composer *> matches, int count)
161 {
162 int n = 0;
163 for (QMultiMap<float, Composer *>::const_iterator i = matches.end();
164 i != matches.begin(); ) {
165 --i;
166 if (i.key() <= 0) continue;
167 cout << endl;
168 if (n == 0) {
169 cout << "Best match:" << endl;
170 } else if (n == 1) {
171 cout << "Other candidate(s):" << endl;
172 }
173 cout << "[" << i.key() << "] ";
174 if (n == 0) show(i.value());
175 else showBrief(i.value());
176 if (++n > count) break;
177 }
178 if (n == 0) cout << "No matches" << endl;
179 cout << endl;
180 }
181
182 void
183 search(QString typing)
184 {
185 cout << "Searching for: " << typing << endl;
186 QMultiMap<float, Composer *> matches;
187 foreach (Composer *c, allComposers) {
188 float value = c->matchTyping(typing);
189 matches.insert(value, c);
190 }
191 showSearchResults(matches, 5);
192 }
193
194 void
195 match(QString text)
196 {
197 cout << "Matching: " << text << endl;
198 QMultiMap<float, Composer *> matches;
199 QRegExp sre("[\\., -]+");
200 QStringList elements = text.toLower().split(sre, QString::SkipEmptyParts);
201 foreach (Composer *c, allComposers) {
202 float value = c->matchFuzzyName(elements);
203 matches.insert(value, c);
204 }
205 showSearchResults(matches, 5);
206 }
207
208 void
209 showWildcard(QString text)
210 {
211 cout << "Showing URI or wildcard: " << text << endl;
212 QRegExp re(text, Qt::CaseInsensitive, QRegExp::Wildcard);
213 foreach (Composer *c, allComposers) {
214 if (re.exactMatch(c->property("uri").value<Uri>().toString())) {
215 cout << endl;
216 show(c);
217 }
218 }
219 cout << endl;
220 }
221
222 int
223 main(int argc, char **argv)
224 {
225 if (argc < 3) usage(argv[0]);
226 QString inFileName = argv[1];
227 QString command = argv[2];
228 QStringList args;
229 for (int i = 3; i < argc; ++i) {
230 args.push_back(argv[i]);
231 }
232
233 BasicStore *store = new BasicStore();
234 store->setBaseUri(Uri("http://dbtune.org/classical/resource/"));
235 ObjectMapper *mapper = new ObjectMapper(store);
236
237 TypeRegistrar::addMappings(store, mapper);
238
239 if (!load(store, inFileName)) {
240 cerr << "Failed to load data source" << endl;
241 return 1;
242 }
243
244 cerr << "Imported RDF data, mapping to objects...";
245 QObject *root = mapper->loadAllObjects(0);
246 cerr << " done" << endl;
247
248 delete mapper;
249 delete store;
250
251 allComposers = root->findChildren<Composer *>();
252
253 QList<Work *> works = root->findChildren<Work *>();
254 foreach (Work *w, works) {
255 Composition *c = w->composition();
256 if (c) {
257 Composer *cp = c->composer();
258 if (cp) worksMap[cp].insert(w);
259 }
260 }
261
262 if (command == "list") {
263 listBrief(allComposers);
264 } else if (command == "list-uris") {
265 listUris(allComposers);
266 } else {
267 if (args.empty()) usage(argv[0]);
268 if (command == "show") {
269 foreach (QString s, args) {
270 if (!s.contains('/') && !s.contains('*')) {
271 s = "*" + s + "*";
272 }
273 showWildcard(s);
274 }
275 } else if (command == "search") {
276 foreach (QString s, args) {
277 search(s);
278 }
279 } else if (command == "match") {
280 foreach (QString s, args) {
281 match(s);
282 }
283 }
284 }
285
286 }
287