blob: 0dabb24e151329a37e745f0777dc11bb95701e3b [file] [log] [blame]
Nils Diewald884dbcf2015-02-27 17:02:28 +00001package de.ids_mannheim.korap.response;
Nils Diewaldf399a672013-11-18 17:55:22 +00002
Nils Diewaldd723d812014-09-23 18:50:52 +00003import com.fasterxml.jackson.annotation.*;
4import com.fasterxml.jackson.annotation.JsonInclude.Include;
Michael Hanl7edaa552014-05-23 18:48:50 +00005import com.fasterxml.jackson.databind.JsonNode;
6import com.fasterxml.jackson.databind.ObjectMapper;
7import com.fasterxml.jackson.databind.SerializationFeature;
8import com.fasterxml.jackson.databind.node.ObjectNode;
Nils Diewald277e9ce2014-11-06 03:42:11 +00009import com.fasterxml.jackson.databind.node.ArrayNode;
Nils Diewaldd723d812014-09-23 18:50:52 +000010
Nils Diewald3caa00d2013-12-13 02:24:04 +000011import de.ids_mannheim.korap.index.PositionsToOffset;
Nils Diewaldf5ab4b22015-02-25 20:55:16 +000012
13// Remove:
Nils Diewald65449ff2015-02-27 17:57:29 +000014import de.ids_mannheim.korap.response.SearchContext;
Nils Diewald392bcf32015-02-26 20:01:17 +000015
Nils Diewald0881e242015-02-27 17:31:01 +000016import de.ids_mannheim.korap.response.Response;
Nils Diewald392bcf32015-02-26 20:01:17 +000017import de.ids_mannheim.korap.response.Match;
Nils Diewald884dbcf2015-02-27 17:02:28 +000018import de.ids_mannheim.korap.Krill;
Nils Diewaldd723d812014-09-23 18:50:52 +000019
Nils Diewaldf399a672013-11-18 17:55:22 +000020import org.slf4j.Logger;
21import org.slf4j.LoggerFactory;
22
Michael Hanl7edaa552014-05-23 18:48:50 +000023import java.util.ArrayList;
24import java.util.List;
Nils Diewaldf399a672013-11-18 17:55:22 +000025
Nils Diewald010c10f2013-12-17 01:58:31 +000026/*
Nils Diewaldbbd39a52015-02-23 19:56:57 +000027 TODO: Reuse the Krill code for data serialization!
Nils Diewald010c10f2013-12-17 01:58:31 +000028*/
Nils Diewaldafab8f32015-01-26 19:11:32 +000029/**
30 * Response class for search results.
Nils Diewaldbb33da22015-03-04 16:24:25 +000031 *
Nils Diewaldcec40f92015-02-19 22:20:02 +000032 * TODO: Synopsis and let it base on KoralQuery
Nils Diewaldbb33da22015-03-04 16:24:25 +000033 *
Nils Diewaldafab8f32015-01-26 19:11:32 +000034 * @author diewald
Nils Diewald0881e242015-02-27 17:31:01 +000035 * @see Response
Nils Diewaldafab8f32015-01-26 19:11:32 +000036 */
Nils Diewaldd723d812014-09-23 18:50:52 +000037@JsonInclude(Include.NON_NULL)
38@JsonIgnoreProperties(ignoreUnknown = true)
Akron98b78542015-08-06 21:43:08 +020039public final class Result extends Krill {
Nils Diewaldf399a672013-11-18 17:55:22 +000040 ObjectMapper mapper = new ObjectMapper();
41
Nils Diewaldd723d812014-09-23 18:50:52 +000042 @JsonIgnore
Nils Diewaldbb33da22015-03-04 16:24:25 +000043 public static final short ITEMS_PER_PAGE = 25;
Nils Diewaldafab8f32015-01-26 19:11:32 +000044 public static final short ITEMS_PER_PAGE_MAX = 100;
Nils Diewaldd723d812014-09-23 18:50:52 +000045
Nils Diewalde1ecd5e2014-11-27 02:17:24 +000046 private int startIndex = 0;
Nils Diewald3aa9e692015-02-20 22:20:11 +000047 private String serialQuery;
Nils Diewaldf399a672013-11-18 17:55:22 +000048
Nils Diewald392bcf32015-02-26 20:01:17 +000049 private List<Match> matches;
Nils Diewaldf399a672013-11-18 17:55:22 +000050
Nils Diewald1e5d5942014-05-20 13:29:53 +000051 private SearchContext context;
52
Nils Diewaldbb33da22015-03-04 16:24:25 +000053 private short itemsPerPage = ITEMS_PER_PAGE, itemsPerResource = 0;
Nils Diewaldf399a672013-11-18 17:55:22 +000054
Nils Diewaldefb9c9a2014-02-20 15:05:18 +000055 private JsonNode request;
56
Nils Diewaldf399a672013-11-18 17:55:22 +000057 // Logger
Nils Diewald884dbcf2015-02-27 17:02:28 +000058 // This is Match instead of Result!
Nils Diewald392bcf32015-02-26 20:01:17 +000059 private final static Logger log = LoggerFactory.getLogger(Match.class);
Nils Diewaldf399a672013-11-18 17:55:22 +000060
Nils Diewaldafab8f32015-01-26 19:11:32 +000061
62 /**
Nils Diewald884dbcf2015-02-27 17:02:28 +000063 * Construct a new Result object.
Nils Diewaldafab8f32015-01-26 19:11:32 +000064 */
Nils Diewaldbb33da22015-03-04 16:24:25 +000065 public Result () {
Nils Diewaldd723d812014-09-23 18:50:52 +000066 mapper.enable(SerializationFeature.INDENT_OUTPUT);
67 };
Nils Diewaldc6b78752013-12-05 19:05:12 +000068
Nils Diewaldafab8f32015-01-26 19:11:32 +000069
70 /**
Nils Diewald884dbcf2015-02-27 17:02:28 +000071 * Construct a new Result object.
Nils Diewaldbb33da22015-03-04 16:24:25 +000072 *
73 * @param serialQuery
74 * Query representation as a string.
75 * @param startIndex
76 * Offset position in match array.
77 * @param itemsPerPage
78 * Number of matches per page.
79 * @param context
80 * Requested {@link SearchContext}
Nils Diewaldafab8f32015-01-26 19:11:32 +000081 */
Nils Diewaldbb33da22015-03-04 16:24:25 +000082 public Result (String query, int startIndex, short itemsPerPage,
83 SearchContext context) {
Nils Diewaldf399a672013-11-18 17:55:22 +000084
Michael Hanl7edaa552014-05-23 18:48:50 +000085 mapper.enable(SerializationFeature.INDENT_OUTPUT);
86 // mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
Nils Diewaldd723d812014-09-23 18:50:52 +000087 // mapper.disable(SerializationFeature.WRITE_NULL_MAP_VALUES);
Nils Diewaldf399a672013-11-18 17:55:22 +000088
Michael Hanl7edaa552014-05-23 18:48:50 +000089 this.matches = new ArrayList<>(itemsPerPage);
Nils Diewald3aa9e692015-02-20 22:20:11 +000090 this.serialQuery = query;
Michael Hanl7edaa552014-05-23 18:48:50 +000091 this.startIndex = startIndex;
Eliza Margaretha6f989202016-10-14 21:48:29 +020092 this.itemsPerPage = (itemsPerPage > ITEMS_PER_PAGE_MAX
93 || itemsPerPage < 1) ? ITEMS_PER_PAGE : itemsPerPage;
Michael Hanl7edaa552014-05-23 18:48:50 +000094 this.context = context;
Nils Diewaldc471b182014-11-19 22:51:15 +000095 };
Nils Diewaldf399a672013-11-18 17:55:22 +000096
Nils Diewaldf399a672013-11-18 17:55:22 +000097
Nils Diewaldafab8f32015-01-26 19:11:32 +000098 /**
99 * Add a new match to the result set.
Nils Diewaldbb33da22015-03-04 16:24:25 +0000100 *
101 * @param match
102 * A {@link Match} to add.
Nils Diewaldafab8f32015-01-26 19:11:32 +0000103 */
Nils Diewald392bcf32015-02-26 20:01:17 +0000104 public void add (Match km) {
Michael Hanl7edaa552014-05-23 18:48:50 +0000105 this.matches.add(km);
Nils Diewaldc471b182014-11-19 22:51:15 +0000106 };
Nils Diewald833fe7e2013-12-14 16:06:33 +0000107
Nils Diewald1e5d5942014-05-20 13:29:53 +0000108
Nils Diewaldafab8f32015-01-26 19:11:32 +0000109 /**
Nils Diewaldd75e6f62015-01-28 23:44:56 +0000110 * Get the number of items (documents) shown per page.
Nils Diewaldbb33da22015-03-04 16:24:25 +0000111 *
Nils Diewaldafab8f32015-01-26 19:11:32 +0000112 * @return Number of items shown per page.
113 */
114 public short getItemsPerPage () {
Michael Hanl7edaa552014-05-23 18:48:50 +0000115 return this.itemsPerPage;
Nils Diewaldc471b182014-11-19 22:51:15 +0000116 };
Nils Diewaldf399a672013-11-18 17:55:22 +0000117
Nils Diewaldafab8f32015-01-26 19:11:32 +0000118
119 /**
Nils Diewaldd75e6f62015-01-28 23:44:56 +0000120 * Set the number of items (documents) shown per page.
Nils Diewaldbb33da22015-03-04 16:24:25 +0000121 *
122 * @param count
123 * Number of items shown per page.
Nils Diewald884dbcf2015-02-27 17:02:28 +0000124 * @return {@link Result} object for chaining.
Nils Diewaldafab8f32015-01-26 19:11:32 +0000125 */
Nils Diewald884dbcf2015-02-27 17:02:28 +0000126 public Result setItemsPerPage (short count) {
Nils Diewaldafab8f32015-01-26 19:11:32 +0000127 this.itemsPerPage = count;
128 return this;
Nils Diewaldea28b622014-10-01 16:01:31 +0000129 };
Nils Diewaldf399a672013-11-18 17:55:22 +0000130
Nils Diewaldafab8f32015-01-26 19:11:32 +0000131
132 /**
133 * Get serialized query as a {@link JsonNode}.
Nils Diewaldbb33da22015-03-04 16:24:25 +0000134 *
Nils Diewaldafab8f32015-01-26 19:11:32 +0000135 * @return {@link JsonNode} representation of the query object.
136 */
137 public JsonNode getRequest () {
Michael Hanl7edaa552014-05-23 18:48:50 +0000138 return this.request;
Nils Diewaldd723d812014-09-23 18:50:52 +0000139 };
Nils Diewaldf399a672013-11-18 17:55:22 +0000140
Nils Diewaldafab8f32015-01-26 19:11:32 +0000141
142 /**
143 * Set serialized query as a {@link JsonNode}.
Nils Diewaldbb33da22015-03-04 16:24:25 +0000144 *
145 * @param request
146 * {@link JsonNode} representation of the query object.
Nils Diewald884dbcf2015-02-27 17:02:28 +0000147 * @return {@link Result} object for chaining.
Nils Diewaldbb33da22015-03-04 16:24:25 +0000148 */
Nils Diewald884dbcf2015-02-27 17:02:28 +0000149 public Result setRequest (JsonNode request) {
Nils Diewaldafab8f32015-01-26 19:11:32 +0000150 this.request = request;
151 return this;
Nils Diewaldc471b182014-11-19 22:51:15 +0000152 };
153
Nils Diewaldc471b182014-11-19 22:51:15 +0000154
Nils Diewaldd75e6f62015-01-28 23:44:56 +0000155 /**
156 * Get the number of items shown per resource (document).
157 * Defaults to <tt>0</tt>, which is infinite.
Nils Diewaldbb33da22015-03-04 16:24:25 +0000158 *
Nils Diewaldd75e6f62015-01-28 23:44:56 +0000159 * @return The number of items shown per resource.
160 */
Nils Diewald7cf8c6d2014-05-28 18:37:38 +0000161 public short getItemsPerResource () {
Nils Diewaldd75e6f62015-01-28 23:44:56 +0000162 return this.itemsPerResource;
Nils Diewald7cf8c6d2014-05-28 18:37:38 +0000163 };
164
Nils Diewaldd75e6f62015-01-28 23:44:56 +0000165
166 /**
167 * Set the number of items (matches) shown per resource (text).
168 * Defaults to <tt>0</tt>, which is infinite.
Nils Diewaldbb33da22015-03-04 16:24:25 +0000169 *
170 * @param value
171 * The number of items shown per resource.
Nils Diewald884dbcf2015-02-27 17:02:28 +0000172 * @return {@link Result} object for chaining.
Nils Diewaldd75e6f62015-01-28 23:44:56 +0000173 */
Nils Diewald884dbcf2015-02-27 17:02:28 +0000174 public Result setItemsPerResource (short value) {
Nils Diewaldd75e6f62015-01-28 23:44:56 +0000175 this.itemsPerResource = value;
176 return this;
177 };
178
179
180 /**
Nils Diewaldbb33da22015-03-04 16:24:25 +0000181 * Set the number of items (matches) shown per resource
182 * (document).
Nils Diewaldd75e6f62015-01-28 23:44:56 +0000183 * Defaults to <tt>0</tt>, which is infinite.
Nils Diewaldbb33da22015-03-04 16:24:25 +0000184 *
185 * @param value
186 * The number of items shown per resource.
Nils Diewald884dbcf2015-02-27 17:02:28 +0000187 * @return {@link Result} object for chaining.
Nils Diewaldd75e6f62015-01-28 23:44:56 +0000188 */
Nils Diewald884dbcf2015-02-27 17:02:28 +0000189 public Result setItemsPerResource (int value) {
Nils Diewaldd75e6f62015-01-28 23:44:56 +0000190 this.itemsPerResource = (short) value;
191 return this;
192 };
193
194
195 /**
196 * Get the string representation of the search query.
Nils Diewaldbb33da22015-03-04 16:24:25 +0000197 *
Nils Diewaldd75e6f62015-01-28 23:44:56 +0000198 * @return The string representation of the search query.
199 */
Nils Diewald3aa9e692015-02-20 22:20:11 +0000200 public String getSerialQuery () {
201 return this.serialQuery;
Nils Diewald277e9ce2014-11-06 03:42:11 +0000202 };
Michael Hanl7edaa552014-05-23 18:48:50 +0000203
Nils Diewaldd75e6f62015-01-28 23:44:56 +0000204
205 /**
Nils Diewald392bcf32015-02-26 20:01:17 +0000206 * Get a certain {@link Match} by index.
Nils Diewaldbb33da22015-03-04 16:24:25 +0000207 *
208 * @param index
209 * The numerical index of the match,
210 * starts with <tt>0</tt>.
Nils Diewald392bcf32015-02-26 20:01:17 +0000211 * @return The {@link Match} object.
Nils Diewaldd75e6f62015-01-28 23:44:56 +0000212 */
Nils Diewaldd723d812014-09-23 18:50:52 +0000213 @JsonIgnore
Nils Diewald392bcf32015-02-26 20:01:17 +0000214 public Match getMatch (int index) {
Michael Hanl7edaa552014-05-23 18:48:50 +0000215 return this.matches.get(index);
Nils Diewald277e9ce2014-11-06 03:42:11 +0000216 };
Michael Hanl7edaa552014-05-23 18:48:50 +0000217
Nils Diewaldd75e6f62015-01-28 23:44:56 +0000218
219 /**
Nils Diewald392bcf32015-02-26 20:01:17 +0000220 * Get the list of {@link Match} matches.
Nils Diewaldbb33da22015-03-04 16:24:25 +0000221 *
Nils Diewald392bcf32015-02-26 20:01:17 +0000222 * @return The list of {@link Match} objects.
Nils Diewaldd75e6f62015-01-28 23:44:56 +0000223 */
Nils Diewaldbb33da22015-03-04 16:24:25 +0000224 public List<Match> getMatches () {
Michael Hanl7edaa552014-05-23 18:48:50 +0000225 return this.matches;
Nils Diewald277e9ce2014-11-06 03:42:11 +0000226 };
Nils Diewaldf399a672013-11-18 17:55:22 +0000227
Nils Diewaldd75e6f62015-01-28 23:44:56 +0000228
229 /**
230 * Get the number of the first match in the result set
231 * (<i>aka</i> the offset). Starts with <tt>0</tt>.
Nils Diewaldbb33da22015-03-04 16:24:25 +0000232 *
Nils Diewaldd75e6f62015-01-28 23:44:56 +0000233 * @return The index number of the first match in the result set.
234 */
Nils Diewald277e9ce2014-11-06 03:42:11 +0000235 public int getStartIndex () {
Michael Hanl7edaa552014-05-23 18:48:50 +0000236 return startIndex;
Nils Diewald277e9ce2014-11-06 03:42:11 +0000237 };
Michael Hanl7edaa552014-05-23 18:48:50 +0000238
Nils Diewaldd75e6f62015-01-28 23:44:56 +0000239
240 /**
241 * Get the context parameters of the search by means of a
242 * {@link SearchContext} object.
Nils Diewaldbb33da22015-03-04 16:24:25 +0000243 *
Nils Diewaldd75e6f62015-01-28 23:44:56 +0000244 * @return The {@link SearchContext} object.
245 */
246 public SearchContext getContext () {
247 return this.context;
248 };
249
250
251 /**
252 * Set the context parameters of the search by means of a
253 * {@link SearchContext} object.
Nils Diewaldbb33da22015-03-04 16:24:25 +0000254 *
255 * @param context
256 * The {@link SearchContext} object providing
257 * search context parameters.
Nils Diewald884dbcf2015-02-27 17:02:28 +0000258 * @return {@link Result} object for chaining.
Nils Diewaldd75e6f62015-01-28 23:44:56 +0000259 */
Nils Diewald884dbcf2015-02-27 17:02:28 +0000260 public Result setContext (SearchContext context) {
Michael Hanl7edaa552014-05-23 18:48:50 +0000261 this.context = context;
262 return this;
Nils Diewaldd75e6f62015-01-28 23:44:56 +0000263 };
Michael Hanl7edaa552014-05-23 18:48:50 +0000264
Nils Diewald1e5d5942014-05-20 13:29:53 +0000265
Nils Diewaldd75e6f62015-01-28 23:44:56 +0000266 /**
267 * Serialize the result set as a {@link JsonNode}.
Nils Diewaldbb33da22015-03-04 16:24:25 +0000268 *
Nils Diewaldd75e6f62015-01-28 23:44:56 +0000269 * @return {@link JsonNode} representation of the search results.
270 */
Nils Diewalde1ecd5e2014-11-27 02:17:24 +0000271 public JsonNode toJsonNode () {
Nils Diewaldd75e6f62015-01-28 23:44:56 +0000272 ObjectNode json = (ObjectNode) mapper.valueToTree(super.toJsonNode());
Akrond7d7b1f2016-06-25 00:31:16 +0200273
Akrond504f212015-06-20 00:27:54 +0200274 this._addMeta(json);
Nils Diewaldc471b182014-11-19 22:51:15 +0000275
Nils Diewaldd75e6f62015-01-28 23:44:56 +0000276 // Add matches
277 if (this.matches != null)
278 json.putPOJO("matches", this.getMatches());
Nils Diewaldc471b182014-11-19 22:51:15 +0000279
Nils Diewaldd75e6f62015-01-28 23:44:56 +0000280 return json;
Nils Diewaldd723d812014-09-23 18:50:52 +0000281 };
Nils Diewald277e9ce2014-11-06 03:42:11 +0000282
Nils Diewaldbb33da22015-03-04 16:24:25 +0000283
Nils Diewaldcd226862015-02-11 22:27:45 +0000284 /**
285 * Stringifies the matches to give a brief overview on
286 * the result. Mainly used for testing.
Nils Diewaldbb33da22015-03-04 16:24:25 +0000287 *
288 * @return The stringified matches
Nils Diewaldcd226862015-02-11 22:27:45 +0000289 */
290 public String getOverview () {
291 StringBuilder sb = new StringBuilder();
292
Nils Diewaldbb33da22015-03-04 16:24:25 +0000293 sb.append("Search for: ").append(this.serialQuery).append("\n");
Nils Diewaldcd226862015-02-11 22:27:45 +0000294
295 int i = 1;
296
297 // Add matches as bracket strings
Nils Diewald392bcf32015-02-26 20:01:17 +0000298 for (Match km : this.getMatches())
Nils Diewaldbb33da22015-03-04 16:24:25 +0000299 sb.append(i++).append(": ").append(km.getSnippetBrackets())
300 .append(" (Doc ").append(km.getLocalDocID()).append(")\n");
Nils Diewaldcd226862015-02-11 22:27:45 +0000301
302 return sb.toString();
303 };
304
Nils Diewald277e9ce2014-11-06 03:42:11 +0000305
306 // For Collocation Analysis API
Nils Diewaldd75e6f62015-01-28 23:44:56 +0000307 @Deprecated
Nils Diewalde1ecd5e2014-11-27 02:17:24 +0000308 public String toTokenListJsonString () {
Akrond504f212015-06-20 00:27:54 +0200309 ObjectNode json = (ObjectNode) mapper.valueToTree(super.toJsonNode());
Akronb1166442015-06-27 00:34:19 +0200310
311 // Meta data for paging
312 ObjectNode meta = json.has("meta") ? (ObjectNode) json.get("meta")
313 : (ObjectNode) json.putObject("meta");
314
315 if (this.context != null)
316 meta.put("context", this.getContext().toJsonNode());
317
318 meta.put("itemsPerPage", this.itemsPerPage);
319 meta.put("startIndex", this.startIndex);
320
321 if (this.itemsPerResource > 0)
322 meta.put("itemsPerResource", this.itemsPerResource);
323
324 if (this.serialQuery != null)
325 meta.put("serialQuery", this.serialQuery);
Nils Diewaldbb33da22015-03-04 16:24:25 +0000326
Nils Diewaldd75e6f62015-01-28 23:44:56 +0000327 ArrayNode array = json.putArray("matches");
Nils Diewaldbb33da22015-03-04 16:24:25 +0000328
Nils Diewaldd75e6f62015-01-28 23:44:56 +0000329 // Add matches as token lists
Nils Diewald392bcf32015-02-26 20:01:17 +0000330 for (Match km : this.getMatches())
Nils Diewaldd75e6f62015-01-28 23:44:56 +0000331 array.add(km.toTokenList());
Nils Diewald277e9ce2014-11-06 03:42:11 +0000332
333 try {
334 return mapper.writeValueAsString(json);
335 }
Nils Diewaldd75e6f62015-01-28 23:44:56 +0000336 catch (Exception e) {
Nils Diewald277e9ce2014-11-06 03:42:11 +0000337 log.warn(e.getLocalizedMessage());
338 };
Nils Diewaldbb33da22015-03-04 16:24:25 +0000339
Nils Diewald277e9ce2014-11-06 03:42:11 +0000340 return "{}";
341 };
Akrond504f212015-06-20 00:27:54 +0200342
343
344 private void _addMeta (ObjectNode json) {
Akronb1166442015-06-27 00:34:19 +0200345 ObjectNode meta = (ObjectNode) this.getMeta().toJsonNode();
Akrond504f212015-06-20 00:27:54 +0200346
Akronb1166442015-06-27 00:34:19 +0200347 // Lucene query for debugging purposes
Akrond504f212015-06-20 00:27:54 +0200348 if (this.serialQuery != null)
349 meta.put("serialQuery", this.serialQuery);
Akrond504f212015-06-20 00:27:54 +0200350
Akronb1166442015-06-27 00:34:19 +0200351 // This may override count
352 meta.put("itemsPerPage", this.itemsPerPage);
Akrond504f212015-06-20 00:27:54 +0200353
Akronb1166442015-06-27 00:34:19 +0200354 if (json.has("meta")) {
355 ((ObjectNode) json.get("meta")).putAll(meta);
356 }
357 else {
358 json.put("meta", meta);
359 };
Akrond504f212015-06-20 00:27:54 +0200360 };
Nils Diewaldf399a672013-11-18 17:55:22 +0000361};