blob: 74dc1c45d2baadf29618d4922c93512b624bd372 [file] [log] [blame]
Nils Diewald7148c6f2015-05-04 15:07:53 +00001package Kalamar::API;
Nils Diewald996aa552014-12-02 03:26:44 +00002use Mojo::Base 'Mojolicious::Plugin';
Nils Diewald791b5902014-12-04 04:47:24 +00003use Scalar::Util qw/blessed weaken/;
Nils Diewald996aa552014-12-02 03:26:44 +00004use strict;
5use warnings;
6
7# KorAP Search engine for Mojolicious::Plugin::Search
8
Nils Diewald7148c6f2015-05-04 15:07:53 +00009# TODO: Add fixtures
10# TODO: Support search in corpus and virtualcollection
11# TODO: Support caching everywhere!
12# TODO: Correct use of stash info everywhere!
Akronf809da22015-06-18 22:08:19 +020013# TODO: Alot is now underneath "meta"
14
Nils Diewald996aa552014-12-02 03:26:44 +000015
16# Register the plugin
17sub register {
18 my ($plugin, $mojo, $index_class, $param) = @_;
19 $param ||= {};
20
21 # Add attributes to the index class
22 $index_class->attr(api => $param->{api});
23 $index_class->attr([qw/cutoff
24 query_language
25 time_exceeded
26 api_request
27 _api_cache
28 api_response
29 benchmark
Akron9cc3eaf2015-06-10 22:15:52 +020030 query_jsonld
Akron27ae9ec2015-06-23 00:43:21 +020031 collection
Akron9cc3eaf2015-06-10 22:15:52 +020032 collection_jsonld/]);
Nils Diewald996aa552014-12-02 03:26:44 +000033 $index_class->attr(no_cache => 0);
34};
35
36
37# Search the index
38sub search {
39 my $self = shift;
40 my $index = shift;
41
Nils Diewald8f4b5da2014-12-03 22:13:39 +000042 # Get controller
Nils Diewald996aa552014-12-02 03:26:44 +000043 my $c = $index->controller;
44
Nils Diewald996aa552014-12-02 03:26:44 +000045 # If there is a callback, do async
46 my $cb = pop if ref $_[-1] && ref $_[-1] eq 'CODE';
47
Nils Diewald8f4b5da2014-12-03 22:13:39 +000048 # No query defined
49 unless ($index->query) {
50 return $cb->($index) if $cb;
51 return;
52 };
Nils Diewald996aa552014-12-02 03:26:44 +000053
Nils Diewald8f4b5da2014-12-03 22:13:39 +000054 # Get query url
55 my $url = _query_url($index, @_);
Nils Diewald996aa552014-12-02 03:26:44 +000056
57 # Cache based on URL
58 $index->_api_cache('total-' . $url->to_string);
Akron27ae9ec2015-06-23 00:43:21 +020059 # TODO: Make this user dependent for collections!!!!
60
Nils Diewald8f4b5da2014-12-03 22:13:39 +000061 my %param = @_;
Nils Diewald996aa552014-12-02 03:26:44 +000062
63 # Set context based on parameter
Nils Diewald8f4b5da2014-12-03 22:13:39 +000064 $url->query({ context => $param{'context'} // 'paragraph' });
65
66 # Set path to search
67 $url->path('search');
Nils Diewald996aa552014-12-02 03:26:44 +000068
69 # Check cache for total results
70 my $total_results;
71
72 if (!$index->no_cache &&
73 defined ($total_results = $c->chi->get($index->_api_cache))) {
74
75 # Set total results from cache
76 $index->total_results($total_results);
77 $c->app->log->debug('Get total result from cache');
78
79 # Set cutoff unless already set
80 $url->query({cutoff => 'true'}) unless defined $index->cutoff;
81 };
82
83 # Set api request for debugging
84 $index->api_request($url->to_string);
85
86 # Create new user agent and set timeout to 2 minutes
Nils Diewald87507832015-05-01 23:36:41 +000087 my $ua = $c->ua;
Nils Diewald996aa552014-12-02 03:26:44 +000088 $ua->inactivity_timeout(120);
89
Nils Diewald8f4b5da2014-12-03 22:13:39 +000090 # Debugging
Nils Diewald996aa552014-12-02 03:26:44 +000091 $c->app->log->debug('Search for ' . $index->api_request);
92
93 # Search non-blocking
94 if ($cb) {
95
Nils Diewald996aa552014-12-02 03:26:44 +000096 $ua->get(
Nils Diewald8f4b5da2014-12-03 22:13:39 +000097 $url => sub {
98 my $tx = pop;
99 $self->_process_response('matches', $index, $tx);
Nils Diewald791b5902014-12-04 04:47:24 +0000100 weaken $index;
Nils Diewald996aa552014-12-02 03:26:44 +0000101 return $cb->($index);
102 });
Nils Diewald996aa552014-12-02 03:26:44 +0000103 }
Nils Diewald87507832015-05-01 23:36:41 +0000104
Nils Diewald996aa552014-12-02 03:26:44 +0000105 # Search blocking
106 else {
107 my $tx = $ua->get($url);
Nils Diewald034ea702015-01-16 19:41:52 +0000108 $self->_process_response('matches', $index, $tx);
109 return $index;
Nils Diewald996aa552014-12-02 03:26:44 +0000110 };
111};
112
113
Nils Diewald8f4b5da2014-12-03 22:13:39 +0000114# Trace query serialization
115sub trace {
116 my $self = shift;
117 my $index = shift;
118
119 # Get controller
120 my $c = $index->controller;
121
122 # If there is a callback, do async
123 my $cb = pop if ref $_[-1] && ref $_[-1] eq 'CODE';
124
125 my %param = @_;
126
127 # No query defined
128 unless ($index->query(delete $param{query})) {
129 return $cb->($index) if $cb;
130 return;
131 };
132
133 # Get query url
134 my $url = _query_url($index, @_);
135
136 $url->path('search');
137
138 # Create new user agent and set timeout to 30 seconds
139 my $ua = $c->ua; # Mojo::UserAgent->new;
140 $ua->inactivity_timeout(30);
141
142 # Build transaction
143 my $tx = $ua->build_tx(TRACE => $url);
144
145 # non-blocking
146 if ($cb) {
Nils Diewald791b5902014-12-04 04:47:24 +0000147 weaken $index;
Nils Diewald8f4b5da2014-12-03 22:13:39 +0000148
149 # Trace non-blocking
150 $ua->start(
151 $tx => sub {
152 $self->_process_response('trace', $index, pop);
153 return $cb->($index);
154 });
155 }
156 # Trace blocking
157 else {
158 my $tx = $ua->start($url);
159 return $self->_process_response('trace', $index, $tx);
160 };
161};
162
163
164# Get match info
165sub match {
166 my $self = shift;
167 my $index = shift;
168
169 # Get controller
170 my $c = $index->controller;
171
172 # If there is a callback, do async
173 my $cb = pop if ref $_[-1] && ref $_[-1] eq 'CODE';
174
175 my %param = @_;
176
177 my $url = Mojo::URL->new($index->api);
178
Nils Diewald87507832015-05-01 23:36:41 +0000179 # Legacy: In old versions, doc_id contained text_id
180 $param{doc_id} .= '.' . $param{text_id} if $param{text_id};
181
Nils Diewald8f4b5da2014-12-03 22:13:39 +0000182 # Use hash slice to create path
183 $url->path(join('/', 'corpus', @param{qw/corpus_id doc_id match_id/}, 'matchInfo'));
184
185 # Build match id
186 # $match = 'match-' . $corpus . '!' . $corpus . '_' . $doc . '-' . $match;
187
188 my %query;
189 $query{foundry} = $param{foundry};
190 $query{layer} = $param{layer} if defined $param{layer};
191 $query{spans} = $param{spans} ? 'true' : 'false';
192
193 # Add query
194 $url->query(\%query);
195
196 $c->app->log->debug('Match info: ' . $url);
197
198 # Create new user agent and set timeout to 30 seconds
199 my $ua = $c->ua; # Mojo::UserAgent->new;
200 $ua->inactivity_timeout(30);
201
202 # non-blocking
203 if ($cb) {
Nils Diewald791b5902014-12-04 04:47:24 +0000204 weaken $index;
Nils Diewald8f4b5da2014-12-03 22:13:39 +0000205 $ua->get(
206 $url => sub {
207 my $tx = pop;
208 $self->_process_response('match', $index, $tx);
209 return $cb->($index);
210 });
211 }
212
213 # Match info blocking
214 else {
215 my $tx = $ua->get($url);
216 return $self->_process_response('match', $index, $tx);
217 };
218};
219
220
Nils Diewald87507832015-05-01 23:36:41 +0000221# Get resource information
Nils Diewald8f4b5da2014-12-03 22:13:39 +0000222sub resource {
223 my $self = shift;
224 my $index = shift;
225
226 # Get controller
227 my $c = $index->controller;
228
229 # If there is a callback, do async
230 my $cb = pop if ref $_[-1] && ref $_[-1] eq 'CODE';
231
232 my %param = @_;
233
234 # Rename info endpoints regarding resource
235 my $type = $param{type} // 'collection';
236 $type = 'virtualcollection' if $type eq 'collection';
237
Nils Diewald87507832015-05-01 23:36:41 +0000238 # Create resource URL
Nils Diewald8f4b5da2014-12-03 22:13:39 +0000239 my $url = Mojo::URL->new($index->api)->path($type);
240
Nils Diewald87507832015-05-01 23:36:41 +0000241 # Debugging
Nils Diewald8f4b5da2014-12-03 22:13:39 +0000242 $c->app->log->debug('Get resource info on '. $url);
243
244 # Check for cached information
245 if (my $json = $c->chi->get($url->to_string)) {
246
Nils Diewald87507832015-05-01 23:36:41 +0000247 # TODO: That's unfortunate, as it prohibits caching of multiple resources
Nils Diewald8f4b5da2014-12-03 22:13:39 +0000248 $c->app->log->debug('Get resource info from cache');
249 $c->stash('search.resource' => $json);
250 return $cb->($index) if $cb;
251 return $json;
252 };
253
254 $c->stash('search._resource_cache' => $url->to_string);
255
256 # Create new user agent and set timeout to 30 seconds
257 my $ua = $c->ua; # Mojo::UserAgent->new;
258 $ua->inactivity_timeout(30);
259
Nils Diewald87507832015-05-01 23:36:41 +0000260 # Get resource information async
Nils Diewald8f4b5da2014-12-03 22:13:39 +0000261 if ($cb) {
Nils Diewald791b5902014-12-04 04:47:24 +0000262 weaken $index;
Nils Diewald8f4b5da2014-12-03 22:13:39 +0000263 $ua->get(
264 $url => sub {
265 $self->_process_response('resource', $index, pop);
266 return $cb->($index);
267 })
268 }
Nils Diewald87507832015-05-01 23:36:41 +0000269
270 # Get resource information blocking
Nils Diewald8f4b5da2014-12-03 22:13:39 +0000271 else {
272 my $tx = $ua->get($url);
273 $self->_process_response('resource', $index, $tx);
274 };
275};
276
277
278# Process response - especially error messages etc.
Nils Diewald996aa552014-12-02 03:26:44 +0000279sub _process_response {
Nils Diewald8f4b5da2014-12-03 22:13:39 +0000280 my ($self, $type, $index, $tx) = @_;
Nils Diewald996aa552014-12-02 03:26:44 +0000281 my $c = $index->controller;
282
283 # An error has occurded
284 if (my $e = $tx->error) {
285 $c->notify(
286 error =>
287 ($e->{code} ? $e->{code} . ': ' : '') .
Akronf55504a2015-06-18 16:42:55 +0200288 $e->{message} . ' for ' . $type . ' (remote)'
Nils Diewald996aa552014-12-02 03:26:44 +0000289 );
290 return;
291 };
292
293 # Response was fine
294 if (my $res = $tx->success) {
295
Nils Diewald996aa552014-12-02 03:26:44 +0000296 # Json failure
297 my $json;
298 unless ($json = $res->json) {
299 $c->notify(error => 'JSON response is invalid');
300 return;
301 };
302
Akron27ae9ec2015-06-23 00:43:21 +0200303 # Set api response as jsonld
304 $index->api_response($json);
305
Nils Diewald8f4b5da2014-12-03 22:13:39 +0000306 # expected response for matches
307 if ($type eq 'matches') {
308 $self->_process_response_matches($index, $json);
309 }
310 elsif ($type eq 'trace') {
311 $self->_process_response_trace($index, $json);
312 }
313 elsif ($type eq 'match') {
314 $self->_process_response_match($index, $json);
315 }
316 elsif ($type eq 'resource') {
317 $self->_process_response_resource($index, $json);
Nils Diewald996aa552014-12-02 03:26:44 +0000318 };
319
Nils Diewald8f4b5da2014-12-03 22:13:39 +0000320 return 1 if ref $json ne 'HASH';
Nils Diewald996aa552014-12-02 03:26:44 +0000321
Akronf55504a2015-06-18 16:42:55 +0200322 $self->_notify_on_warnings($c, $json);
Nils Diewald996aa552014-12-02 03:26:44 +0000323 $self->_notify_on_error($c, 0, $json);
324 }
325
326 # Request failed
327 else {
328 $self->_notify_on_error($c, 1, $tx->res);
329 };
330 return 1;
331};
332
333
Nils Diewald87507832015-05-01 23:36:41 +0000334# Handle match results
Nils Diewald8f4b5da2014-12-03 22:13:39 +0000335sub _process_response_matches {
336 my ($self, $index, $json) = @_;
Nils Diewald996aa552014-12-02 03:26:44 +0000337
Akron27ae9ec2015-06-23 00:43:21 +0200338 # Process meta
339 my $meta = $json->{meta};
340
Nils Diewald8f4b5da2014-12-03 22:13:39 +0000341 # Reformat benchmark counter
Akron27ae9ec2015-06-23 00:43:21 +0200342 my $benchmark = $meta->{benchmark};
Nils Diewald8f4b5da2014-12-03 22:13:39 +0000343 if ($benchmark && $benchmark =~ s/\s+(m)?s$//) {
344 $benchmark = sprintf("%.2f", $benchmark) . ($1 ? $1 : '') . 's';
345 };
346
347 # Set benchmark
348 $index->benchmark($benchmark);
349
350 # Set time exceeded
Akron27ae9ec2015-06-23 00:43:21 +0200351 if ($meta->{timeExceeded} && $meta->{timeExceeded} eq Mojo::JSON::true) {
Nils Diewald8f4b5da2014-12-03 22:13:39 +0000352 $index->time_exceeded(1);
353 };
354
355 # Set result values
Akron27ae9ec2015-06-23 00:43:21 +0200356 $index->items_per_page($meta->{itemsPerPage});
357
Akron9cc3eaf2015-06-10 22:15:52 +0200358
Akronc1457bf2015-06-11 19:24:00 +0200359 # Bouncing query
Akron27ae9ec2015-06-23 00:43:21 +0200360# if ($json->{query}) {
361# $index->query_jsonld($json->{query});
362# };
363
Akronc1457bf2015-06-11 19:24:00 +0200364 # Legacy
Akron27ae9ec2015-06-23 00:43:21 +0200365 # elsif ($json->{request}->{query}) {
366 # $index->query_jsonld($json->{request}->{query});
367 # };
Akronc1457bf2015-06-11 19:24:00 +0200368
369 # Bouncing collection query
370 if ($json->{collection}) {
371 $index->collection_jsonld($json->{collection});
372 }
373
374 # Legacy
Akron27ae9ec2015-06-23 00:43:21 +0200375 # elsif ($json->{request}->{collection}) {
376 # $index->collection_jsonld($json->{request}->{collection});
377 # };
Akron48b1e4d2015-06-17 18:47:01 +0200378
Nils Diewald8f4b5da2014-12-03 22:13:39 +0000379 $index->results(_map_matches($json->{matches}));
380
381 # Total results not set by stash
382 if ($index->total_results == -1) {
383
Akron27ae9ec2015-06-23 00:43:21 +0200384 if ($meta->{totalResults} && $meta->{totalResults} > -1) {
Nils Diewald8f4b5da2014-12-03 22:13:39 +0000385 my $c = $index->controller;
386
387 $c->app->log->debug('Cache total result');
Akron27ae9ec2015-06-23 00:43:21 +0200388 $c->chi->set($index->_api_cache => $meta->{totalResults}, '120min');
389 $index->total_results($meta->{totalResults});
Nils Diewald8f4b5da2014-12-03 22:13:39 +0000390 };
391 };
392};
393
394
395# Process query serialization response
396sub _process_response_match {
397 my ($self, $index, $json) = @_;
398 $index->results(_map_match($json));
399};
400
401
Nils Diewald87507832015-05-01 23:36:41 +0000402# Process trace response
Nils Diewald8f4b5da2014-12-03 22:13:39 +0000403sub _process_response_trace {
404 my ($self, $index, $json) = @_;
405 $index->query_jsonld($json);
406};
407
Nils Diewald87507832015-05-01 23:36:41 +0000408
409# Process resource response
Nils Diewald8f4b5da2014-12-03 22:13:39 +0000410sub _process_response_resource {
411 my ($self, $index, $json) = @_;
412 my $c = $index->controller;
413
414 # TODO: That's unfortunate, as it prohibits multiple resources
415 $c->stash('search.resource' => $json);
416 $c->app->log->debug('Cache resource info');
417 $c->chi->set($c->stash('search._resource_cache') => $json, '24 hours');
418};
419
420
Nils Diewald87507832015-05-01 23:36:41 +0000421# Parse error messages and forward them to the user
Nils Diewald996aa552014-12-02 03:26:44 +0000422sub _notify_on_error {
423 my ($self, $c, $failure, $res) = @_;
424 my $json = $res;
425
426 my $log = $c->app->log;
427
Nils Diewald8f4b5da2014-12-03 22:13:39 +0000428 # Check if the response is already json
Nils Diewald996aa552014-12-02 03:26:44 +0000429 if (blessed $res) {
Nils Diewald8f4b5da2014-12-03 22:13:39 +0000430 $json = $res->json if blessed $res ne 'Mojo::JSON';
Nils Diewald996aa552014-12-02 03:26:44 +0000431 };
432
Akronf55504a2015-06-18 16:42:55 +0200433 # Check json response error message
Nils Diewald996aa552014-12-02 03:26:44 +0000434 if ($json) {
Akron27ae9ec2015-06-23 00:43:21 +0200435
436 # Legacy, but still in use by Kustvakt
Nils Diewald996aa552014-12-02 03:26:44 +0000437 if ($json->{error}) {
Akron27ae9ec2015-06-23 00:43:21 +0200438
Nils Diewald996aa552014-12-02 03:26:44 +0000439 # Temp
440 $json->{error} =~ s/;\s+null$//;
441 $c->notify(error => $json->{error});
442 return;
443 }
444
445 # New error messages
446 elsif ($json->{errstr}) {
447 # Temp
448 $json->{errstr} =~ s/;\s+null$//;
449 $c->notify(error => $json->{errstr});
450 return;
451 }
452
Akronf55504a2015-06-18 16:42:55 +0200453 elsif ($json->{errors}) {
454 my $errors = $json->{errors};
455 # TODO: Check for ref!
456 foreach (@$errors) {
457 $c->notify(
458 error =>
459 ($_->[0] ? $_->[0] . ': ' : '') .
460 $_->[1]
461 );
462 };
463 }
464
Nils Diewald996aa552014-12-02 03:26:44 +0000465 # policy service error messages
466 elsif ($json->{status}) {
467 $c->notify(error => 'Middleware error ' . $json->{status});
468 return;
469 };
470 };
471
Nils Diewald8f4b5da2014-12-03 22:13:39 +0000472 # Doesn't matter what - there is a failure!
Nils Diewald996aa552014-12-02 03:26:44 +0000473 if ($failure) {
474 $c->notify(error => (
475 ($res->{code} ? $res->{code} . ': ' : '') .
476 ($res->{message} ? $res->{message} : 'Unknown error') .
477 ' (remote)'
478 ));
479 };
480};
481
482
Akronf55504a2015-06-18 16:42:55 +0200483sub _notify_on_warnings {
484 my ($self, $c, $json) = @_;
485
486 # Add warnings (Legacy)
487 if ($json->{warning}) {
488 $json->{warning} =~ s/;\s+null$//;
489 $c->notify(warn => $json->{warning});
490 }
491
492 # Add warnings
493 elsif ($json->{warnings}) {
494
495 my $warnings = $json->{warnings};
496 # TODO: Check for ref!
497 foreach (@$warnings) {
498 $c->notify(
499 warn =>
500 ($_->[0] ? $_->[0] . ': ' : '') .
501 $_->[1]
502 );
503 };
504 };
505};
506
507
Nils Diewald8f4b5da2014-12-03 22:13:39 +0000508# Cleanup array of matches
Nils Diewald996aa552014-12-02 03:26:44 +0000509sub _map_matches {
510 return () unless $_[0];
Nils Diewald8f4b5da2014-12-03 22:13:39 +0000511 map { _map_match($_) } @{ shift() };
512};
513
514
515# Cleanup single match
516sub _map_match {
517 my $x = shift or return;
518 $x->{ID} =~ s/^match\-[^!]+![^-]+-//;
519 $x->{docID} =~ s/^[^_]+_//;
Nils Diewald87507832015-05-01 23:36:41 +0000520
521 # Legacy: In old versions the text_id was part of the doc_id
522 unless ($x->{textID}) {
Nils Diewald4347ee92015-05-04 20:32:48 +0000523 ($x->{docID}, $x->{textID}) = split '\.', $x->{docID};
Nils Diewald87507832015-05-01 23:36:41 +0000524 };
Nils Diewald8f4b5da2014-12-03 22:13:39 +0000525 $x;
526};
527
528
Nils Diewald87507832015-05-01 23:36:41 +0000529# Build query url
Nils Diewald8f4b5da2014-12-03 22:13:39 +0000530sub _query_url {
531 my ($index, %param) = @_;
532
533 # Set cutoff from param
534 $index->cutoff(delete $param{cutoff});
535
Akron27ae9ec2015-06-23 00:43:21 +0200536 # Set collection from param
537 $index->collection(delete $param{collection});
538
Nils Diewald8f4b5da2014-12-03 22:13:39 +0000539 # Set query language
540 $index->query_language(delete $param{query_language} // 'poliqarp');
541
542 # Should results be cached? Defaults to "yes"
543 $index->no_cache(1) if $param{no_cache};
544
545 # Init the query with stuff coming from the index
546 my %query;
547 $query{q} = $index->query;
548 $query{ql} = $index->query_language;
549 $query{page} = $index->start_page if $index->start_page;
550 $query{count} = $index->items_per_page if $index->items_per_page;
Akron27ae9ec2015-06-23 00:43:21 +0200551 $query{cq} = $index->collection if $index->collection;
Nils Diewald8f4b5da2014-12-03 22:13:39 +0000552 $query{cutoff} = 'true' if $index->cutoff;
553
Nils Diewald8f4b5da2014-12-03 22:13:39 +0000554 # Create query url
555 my $url = Mojo::URL->new($index->api);
556 $url->query(\%query);
557 return $url;
Nils Diewald996aa552014-12-02 03:26:44 +0000558};
559
560
5611;
562
Nils Diewald8f4b5da2014-12-03 22:13:39 +0000563
Nils Diewald996aa552014-12-02 03:26:44 +0000564__END__
565
566=pod
567
Nils Diewald9dfe0102015-05-19 16:14:06 +0000568=encoding utf8
Nils Diewald996aa552014-12-02 03:26:44 +0000569
Nils Diewald9dfe0102015-05-19 16:14:06 +0000570=head1 NAME
571
572Kalamar::API
573
574=head1 DESCRIPTION
575
576L<Kalamar::API> is a search engine class for L<Mojolicious::Plugin::Search>
577that uses the KorAP Web API.
578
579B<The Web API as well as L<Mojolicious::Plugin::Search> are not stable yet,
580so this class is expected to change in the near future. Do not rely on its API!>
581
582
583=head1 METHODS
584
585L<Kalamar::API> inherits all methods from L<Mojolicious::Plugin> and
586implements the following new ones.
587
588
589=head2 register
590
591See L<Mojolicious::Plugin::Search> for registering search engines.
592In addition to the mentioned query parameters, the following parameters are supported:
593
594
595=over 2
596
597=item B<query_language>
598
599One of the supported query languages, like C<poliqarp> or C<annis>.
600
601
602=item B<cutoff>
603
604Cut off results following the current page (i.e. don't count the number of results).
605
606
607=item B<no_cache>
608
609Do not cache search results. Defaults to C<0>.
610
611
612=back
613
614In addition to the mentioned index attributes, the following attributes are supported:
615
Akron456abd92015-06-02 15:07:21 +0200616=over 2
Nils Diewald9dfe0102015-05-19 16:14:06 +0000617
618=item B<api>
619
620The API address.
621
622
623=item B<time_exceeded>
624
625Report on time outs, that may mean, not all results were retrieved.
626
627
628=item B<api_request>
629
630Report the whole API request.
631
632
633=item B<api_response>
634
635Report the whole API response (a KoralQuery object).
636
637
638=item B<benchmarks>
639
640Report on processing time for benchmarking.
641
642
643=item B<query_jsonld>
644
645The KoralQuery realization of the C<query> object.
646
647=back
648
649=head2 search
650
651Search the index.
652
653=head2 trace
654
655Trace query serializations.
656
657=head2 match
658
659Get match information.
660
661=head2 resource
662
663Get resource information.
664
665
666=head1 COPYRIGHT AND LICENSE
667
668Copyright (C) 2015, L<IDS Mannheim|http://www.ids-mannheim.de/>
669Author: L<Nils Diewald|http://nils-diewald.de/>
670
671Kalamar is developed as part of the L<KorAP|http://korap.ids-mannheim.de/>
672Corpus Analysis Platform at the
673L<Institute for the German Language (IDS)|http://ids-mannheim.de/>,
674member of the
675L<Leibniz-Gemeinschaft|http://www.leibniz-gemeinschaft.de/en/about-us/leibniz-competition/projekte-2011/2011-funding-line-2/>
676and supported by the L<KobRA|http://www.kobra.tu-dortmund.de> project,
677funded by the
678L<Federal Ministry of Education and Research (BMBF)|http://www.bmbf.de/en/>.
679
680Kalamar is free software published under the
Akron456abd92015-06-02 15:07:21 +0200681L<BSD-2 License|https://raw.githubusercontent.com/KorAP/Kalamar/master/LICENSE>.
Nils Diewald9dfe0102015-05-19 16:14:06 +0000682
683=cut
Akron27ae9ec2015-06-23 00:43:21 +0200684
685 # Temporary:
686 my $collection_query = {
687 '@type' => "koral:docGroup",
688 "operation" => "operation:or",
689 "operands" => [
690 {
691 '@type' => "koral:docGroup",
692 "operation" => "operation:and",
693 "operands" => [
694 {
695 '@type' => "koral:doc",
696 "key" => "title",
697 "match" => "match:eq",
698 "value" => "Der Birnbaum",
699 "type" => "type:string"
700 },
701 {
702 '@type' => "koral:doc",
703 "key" => "pubPlace",
704 "match" => "match:eq",
705 "value" => "Mannheim",
706 "type" => "type:string"
707 },
708 {
709 '@type' => "koral:docGroup",
710 "operation" => "operation:or",
711 "operands" => [
712 {
713 '@type' => "koral:doc",
714 "key" => "subTitle",
715 "match" => "match:eq",
716 "value" => "Aufzucht oder Pflege",
717 "type" => "type:string"
718 },
719 {
720 '@type' => "koral:doc",
721 "key" => "subTitle",
722 "match" => "match:eq",
723 "value" => "Gedichte",
724 "type" => "type:string"
725 }
726 ]
727 }
728 ]
729 },
730 {
731 '@type' => "koral:doc",
732 "key" => "pubDate",
733 "match" => "match:geq",
734 "value" => "2015-03-05",
735 "type" => "type:date"
736 }
737 ]
738 };