blob: 97cb24f4e8c6eee68b3ad02c40bfd6b73888d745 [file] [log] [blame]
Nils Diewaldf399a672013-11-18 17:55:22 +00001package de.ids_mannheim.korap.query.wrap;
2
Eliza Margaretha369e7562015-02-09 17:36:24 +00003import java.util.ArrayList;
Nils Diewaldbe5943e2014-10-21 19:35:34 +00004
Nils Diewaldf399a672013-11-18 17:55:22 +00005import org.apache.lucene.index.Term;
Eliza Margaretha369e7562015-02-09 17:36:24 +00006import org.apache.lucene.search.spans.SpanQuery;
7import org.apache.lucene.search.spans.SpanTermQuery;
Nils Diewalddc8dc342014-07-25 13:38:50 +00008import org.slf4j.Logger;
9import org.slf4j.LoggerFactory;
10
Eliza Margaretha369e7562015-02-09 17:36:24 +000011import de.ids_mannheim.korap.query.DistanceConstraint;
12import de.ids_mannheim.korap.query.SpanDistanceQuery;
13import de.ids_mannheim.korap.query.SpanElementQuery;
14import de.ids_mannheim.korap.query.SpanExpansionQuery;
15import de.ids_mannheim.korap.query.SpanMultipleDistanceQuery;
16import de.ids_mannheim.korap.query.SpanNextQuery;
17import de.ids_mannheim.korap.util.QueryException;
18
Nils Diewaldcc7c0b32014-07-31 19:58:22 +000019/*
Nils Diewald0cc4f2e2015-01-30 20:13:08 +000020 TODO: Make isNegative work!
21 TODO: Make isEmpty work!
22 TODO: Make isExtendedToTheRight work!
23 TODO: Evaluate if spanNext(spanNext(a,b),spanNext(c,d)) is faster
24 than spanNext(spanNext(spanNext(a,b),c),d)
25 TODO: Improve support for SpanElementQueryWrapper in constraints!
Nils Diewaldcc7c0b32014-07-31 19:58:22 +000026*/
27
Nils Diewaldf399a672013-11-18 17:55:22 +000028/**
Nils Diewald0cc4f2e2015-01-30 20:13:08 +000029 * Deserialize complexe sequence queries to SpanQueries.
30 * This will try to make queries work, that by simple nesting won't
31 * (like queries with empty sequences), and will optimize queries
32 * if possible.
Nils Diewald92729ce2014-10-06 16:00:17 +000033 *
Nils Diewald0cc4f2e2015-01-30 20:13:08 +000034 * Todo: Synopsis
35 *
36 * @author diewald
Nils Diewaldf399a672013-11-18 17:55:22 +000037 */
Nils Diewald92729ce2014-10-06 16:00:17 +000038public class SpanSequenceQueryWrapper extends SpanQueryWrapper {
Nils Diewaldf399a672013-11-18 17:55:22 +000039 private String field;
Nils Diewaldbe5943e2014-10-21 19:35:34 +000040 private ArrayList<SpanQueryWrapper> segments;
Nils Diewaldd7cb0eb2014-02-12 23:06:10 +000041 private ArrayList<DistanceConstraint> constraints;
Nils Diewalddc8dc342014-07-25 13:38:50 +000042
Nils Diewald0cc4f2e2015-01-30 20:13:08 +000043 private QueryException constraintException = null;
44
Nils Diewald8db8f922014-10-24 17:43:13 +000045 private final String limitationError =
Nils Diewald6409a922015-01-29 20:50:42 +000046 "Distance constraints not supported with " +
47 "empty or negative operands";
Nils Diewald8db8f922014-10-24 17:43:13 +000048
Nils Diewalddc8dc342014-07-25 13:38:50 +000049 // Logger
Nils Diewald6409a922015-01-29 20:50:42 +000050 private final static Logger log =
51 LoggerFactory.getLogger(SpanSequenceQueryWrapper.class);
Nils Diewalddc8dc342014-07-25 13:38:50 +000052
53 // This advices the java compiler to ignore all loggings
Nils Diewaldbe5943e2014-10-21 19:35:34 +000054 public static final boolean DEBUG = false;
Nils Diewaldd7cb0eb2014-02-12 23:06:10 +000055
Nils Diewaldbe5943e2014-10-21 19:35:34 +000056 private boolean isInOrder = true;
57
Nils Diewald8db8f922014-10-24 17:43:13 +000058 // The sequence is problem solved
59 private boolean isSolved = false;
60
Nils Diewald6409a922015-01-29 20:50:42 +000061
Nils Diewaldbe5943e2014-10-21 19:35:34 +000062 /**
Nils Diewald0cc4f2e2015-01-30 20:13:08 +000063 * Constructs a new object for sequence deserialization.
64 *
65 * @param field The fields the nested SpanQueries should
66 * search in.
Nils Diewaldbe5943e2014-10-21 19:35:34 +000067 */
Nils Diewaldf399a672013-11-18 17:55:22 +000068 public SpanSequenceQueryWrapper (String field) {
Nils Diewald6409a922015-01-29 20:50:42 +000069 this.field = field;
70 this.segments = new ArrayList<SpanQueryWrapper>(2);
Nils Diewaldf399a672013-11-18 17:55:22 +000071 };
72
Nils Diewaldbe5943e2014-10-21 19:35:34 +000073
74 /**
Nils Diewald0cc4f2e2015-01-30 20:13:08 +000075 * Constructs a new object for sequence deserialization
76 * by passing a sequence of terms.
77 *
78 * <blockquote><pre>
79 * SpanSequenceQueryWrapper ssqw =
80 * new SpanSequenceQueryWrapper("tokens", "der", "Baum");
81 * System.out.println(ssqw.toQuery());
82 * // spanNext(tokens:der, tokens:Baum)
83 * </pre></blockquote>
84 *
85 * @param field The fields the nested SpanQueries should
86 * search in.
87 * @param terms[] Arbitrary list of terms to search for.
Nils Diewaldbe5943e2014-10-21 19:35:34 +000088 */
Nils Diewaldf399a672013-11-18 17:55:22 +000089 public SpanSequenceQueryWrapper (String field, String ... terms) {
Nils Diewald6409a922015-01-29 20:50:42 +000090 this(field);
91 for (int i = 0; i < terms.length; i++) {
92 this.segments.add(
Nils Diewaldbe5943e2014-10-21 19:35:34 +000093 new SpanSimpleQueryWrapper(
94 new SpanTermQuery(new Term(field, terms[i]))
95 )
96 );
Nils Diewald6409a922015-01-29 20:50:42 +000097 };
Nils Diewald0cc4f2e2015-01-30 20:13:08 +000098 // Query can't be null anymore
Nils Diewald6409a922015-01-29 20:50:42 +000099 this.isNull = false;
Nils Diewaldf399a672013-11-18 17:55:22 +0000100 };
101
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000102
103 /**
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000104 * Constructs a new object for sequence deserialization
105 * by passing a single {@link SpanQuery} object.
106 *
107 * @param query Initial {@link SpanQuery} to search for.
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000108 */
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000109 public SpanSequenceQueryWrapper (SpanQuery query) {
110 this(query.getField());
111 this.segments.add(new SpanSimpleQueryWrapper(query));
Nils Diewald6409a922015-01-29 20:50:42 +0000112 this.isNull = false;
Nils Diewaldf399a672013-11-18 17:55:22 +0000113 };
114
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000115
116 /**
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000117 * Constructs a new object for sequence deserialization
118 * by passing a single {@link SpanQueryWrapper} object.
119 * These wrapper queries may be optional, negative, or empty.
120 *
121 * @param query Initial {@link SpanQueryWrapper} to search for.
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000122 */
Nils Diewald92729ce2014-10-06 16:00:17 +0000123 public SpanSequenceQueryWrapper (String field, SpanQueryWrapper sswq) {
Nils Diewald6409a922015-01-29 20:50:42 +0000124 this(field);
Nils Diewaldcc7c0b32014-07-31 19:58:22 +0000125
Nils Diewald6409a922015-01-29 20:50:42 +0000126 // Ignore null queries
127 if (sswq.isNull())
128 return;
Nils Diewaldcc7c0b32014-07-31 19:58:22 +0000129
Nils Diewald0981c212015-02-13 20:47:10 +0000130 if (sswq.maybeUnsorted())
131 this.maybeUnsorted = true;
132
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000133 // Some debugging on initiating new sequences
134 if (DEBUG) {
135 if (!sswq.isEmpty()) {
136 try {
137 log.trace("New span sequence {}", sswq.toQuery().toString());
138 }
139 catch (QueryException qe) {
140 log.trace("Unable to serialize query {}", qe.getMessage());
141 };
Nils Diewald6409a922015-01-29 20:50:42 +0000142 }
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000143 else {
144 log.trace("New span sequence, that's initially empty");
Nils Diewald6409a922015-01-29 20:50:42 +0000145 };
146 };
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000147
Nils Diewald6409a922015-01-29 20:50:42 +0000148 this.segments.add(sswq);
149 this.isNull = false;
Nils Diewaldf399a672013-11-18 17:55:22 +0000150 };
151
Nils Diewald6b332812014-07-22 18:51:05 +0000152
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000153
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000154 /**
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000155 * Append a new term to the sequence.
156 *
157 * <blockquote><pre>
158 * SpanSequenceQueryWrapper ssqw =
159 * new SpanSequenceQueryWrapper("tokens");
160 * ssqw.append("der").append("Baum");
161 * System.out.println(ssqw.toQuery());
162 * // spanNext(tokens:der, tokens:Baum)
163 * </pre></blockquote>
164 *
165 * @param term A new string to search for.
166 * @return The {@link SpanSequenceQueryWrapper} object for chaining.
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000167 */
Nils Diewaldf399a672013-11-18 17:55:22 +0000168 public SpanSequenceQueryWrapper append (String term) {
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000169 return this.append(new SpanTermQuery(new Term(field, term)));
Nils Diewald602c9222014-07-23 19:49:53 +0000170 };
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000171
172
173 /**
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000174 * Append a new {@link SpanQuery} object to the sequence.
175 *
176 * @param query A new {@link SpanQuery} to search for.
177 * @return The {@link SpanSequenceQueryWrapper} object for chaining.
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000178 */
Nils Diewald602c9222014-07-23 19:49:53 +0000179 public SpanSequenceQueryWrapper append (SpanQuery query) {
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000180 return this.append(new SpanSimpleQueryWrapper(query));
Nils Diewaldf399a672013-11-18 17:55:22 +0000181 };
182
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000183
184 /**
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000185 * Append a new {@link SpanQueryWrapper} object to the sequence.
186 *
187 * @param query A new {@link SpanQueryWrapper} to search for.
188 * @return The {@link SpanSequenceQueryWrapper} object for chaining.
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000189 */
Eliza Margaretha369e7562015-02-09 17:36:24 +0000190 public SpanSequenceQueryWrapper append(SpanQueryWrapper ssq) {
Nils Diewald92729ce2014-10-06 16:00:17 +0000191
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000192 // The wrapper is null - ignore this in the sequence
193 if (ssq.isNull())
194 return this;
Nils Diewald8db8f922014-10-24 17:43:13 +0000195
Nils Diewald0981c212015-02-13 20:47:10 +0000196 if (ssq.maybeUnsorted())
197 this.maybeUnsorted = true;
198
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000199 // As the spanQueryWrapper is not null,
200 // the sequence can't be null as well
201 this.isNull = false;
Nils Diewald8db8f922014-10-24 17:43:13 +0000202
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000203 // The sequence may be problematic
204 this.isSolved = false;
Nils Diewaldb84e7272014-11-07 01:27:38 +0000205
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000206 // Embed a nested sequence
207 if (ssq instanceof SpanSequenceQueryWrapper) {
Nils Diewaldb84e7272014-11-07 01:27:38 +0000208
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000209 if (DEBUG)
210 log.trace("Add SpanSequenceQueryWrapper to sequence");
Nils Diewald8db8f922014-10-24 17:43:13 +0000211
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000212 // Some casting
213 SpanSequenceQueryWrapper ssqw = (SpanSequenceQueryWrapper) ssq;
Nils Diewald92729ce2014-10-06 16:00:17 +0000214
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000215 // There are no constraints and the order is equal - Flatten!
216 if (!this.hasConstraints() && !ssqw.hasConstraints() &&
217 this.isInOrder() == ssqw.isInOrder()) {
218 for (int i = 0; i < ssqw.segments.size(); i++) {
219 this.append(ssqw.segments.get(i));
220 };
221 }
222
223 // Unable to flatten ... :-(
224 else {
225 this.segments.add(ssq);
226 };
227 }
228
229 // This is not a sequence
230 else {
231 this.segments.add(ssq);
232 };
233
234 return this;
Nils Diewaldf399a672013-11-18 17:55:22 +0000235 };
236
Nils Diewald8db8f922014-10-24 17:43:13 +0000237
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000238 /**
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000239 * Prepend a new term to the sequence.
240 *
241 * <blockquote><pre>
242 * SpanSequenceQueryWrapper ssqw =
243 * new SpanSequenceQueryWrapper("tokens", "Baum");
244 * ssqw.prepend("der");
245 * System.out.println(ssqw.toQuery());
246 * // spanNext(tokens:der, tokens:Baum)
247 * </pre></blockquote>
248 *
249 * @param term A new string to search for.
250 * @return The {@link SpanSequenceQueryWrapper} object for chaining.
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000251 */
Nils Diewaldf399a672013-11-18 17:55:22 +0000252 public SpanSequenceQueryWrapper prepend (String term) {
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000253 return this.prepend(new SpanTermQuery(new Term(field, term)));
Nils Diewald602c9222014-07-23 19:49:53 +0000254 };
255
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000256
257 /**
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000258 * Prepend a new {@link SpanQuery} object to the sequence.
259 *
260 * @param query A new {@link SpanQuery} to search for.
261 * @return The {@link SpanSequenceQueryWrapper} object for chaining.
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000262 */
Nils Diewald602c9222014-07-23 19:49:53 +0000263 public SpanSequenceQueryWrapper prepend (SpanQuery query) {
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000264 return this.prepend(new SpanSimpleQueryWrapper(query));
Nils Diewaldf399a672013-11-18 17:55:22 +0000265 };
266
Nils Diewald8db8f922014-10-24 17:43:13 +0000267
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000268 /**
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000269 * Prepend a new {@link SpanQueryWrapper} object to the sequence.
270 *
271 * @param query A new {@link SpanQueryWrapper} to search for.
272 * @return The {@link SpanSequenceQueryWrapper} object for chaining.
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000273 */
Nils Diewald92729ce2014-10-06 16:00:17 +0000274 public SpanSequenceQueryWrapper prepend (SpanQueryWrapper ssq) {
Nils Diewaldcc7c0b32014-07-31 19:58:22 +0000275
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000276 // The wrapper is null - ignore this in the sequence
277 if (ssq.isNull())
278 return this;
Nils Diewald8db8f922014-10-24 17:43:13 +0000279
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000280 // As the spanQueryWrapper is not null,
281 // the sequence can't be null as well
282 this.isNull = false;
Nils Diewald8db8f922014-10-24 17:43:13 +0000283
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000284 // The sequence may be problematic
285 this.isSolved = false;
Nils Diewaldb84e7272014-11-07 01:27:38 +0000286
Nils Diewald0981c212015-02-13 20:47:10 +0000287 if (ssq.maybeUnsorted())
288 this.maybeUnsorted = true;
289
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000290 // Embed a nested sequence
291 if (ssq instanceof SpanSequenceQueryWrapper) {
Nils Diewald8db8f922014-10-24 17:43:13 +0000292
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000293 // There are no constraints and the order is equal - Flatten!
294 SpanSequenceQueryWrapper ssqw = (SpanSequenceQueryWrapper) ssq;
295 if (!this.hasConstraints() &&
296 !ssqw.hasConstraints() &&
297 this.isInOrder() == ssqw.isInOrder()) {
298 for (int i = ssqw.segments.size() - 1; i >= 0; i--) {
299 this.prepend(ssqw.segments.get(i));
300 };
301 }
Nils Diewaldff631ae2014-07-24 13:03:17 +0000302
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000303 // Unable to flatten ... :-(
304 else {
305 this.segments.add(0, ssq);
306 };
307 }
308
309 // This is not a sequence
310 else {
311 this.segments.add(0, ssq);
312 };
313
314 return this;
Nils Diewaldf399a672013-11-18 17:55:22 +0000315 };
316
Nils Diewald6b332812014-07-22 18:51:05 +0000317
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000318 /**
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000319 * Add a token based sequence constraint (aka distance constraint)
320 * to the sequence.
321 *
322 * Multiple constraints are supported.
323 *
324 * A minimum value of zero means, there may be an overlap,
325 * a minimum value of 1 means, there is no token between the spans.
326 * It's weird - we know and dislike that. That's why we have to say:
327 *
328 * <strong>Warning!</strong> Sequence constraints are experimental and
329 * may (hopefully) change in future versions!
330 *
331 * @param min The minimum number of tokens between the elements
332 * of the sequence.
333 * @param max The minimum number of tokens between the elements
334 * of the sequence.
335 * @return The {@link SpanSequenceQueryWrapper} object for chaining.
336 * @see DistanceConstraint
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000337 */
Nils Diewaldd7cb0eb2014-02-12 23:06:10 +0000338 public SpanSequenceQueryWrapper withConstraint (int min, int max) {
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000339 return this.withConstraint(min, max, false);
Nils Diewald8c543432014-02-27 18:25:38 +0000340 };
341
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000342
343 /**
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000344 * Add a token based sequence constraint (aka distance constraint)
345 * to the sequence with an exclusion constraint, meaning
346 * the constraint is fine in case the operands are <em>not</em>
347 * within the distance.
348 *
349 * Multiple constraints are supported.
350 *
351 * A minimum value of zero means, there may be an overlap,
352 * a minimum value of 1 means, there is no token between the spans.
353 * It's weird - we know and dislike that. That's why we have to say:
354 *
355 * <strong>Warning!</strong> Sequence constraints are experimental and
356 * may (hopefully) change in future versions!
357 *
358 * @param min The minimum number of tokens between the elements
359 * of the sequence.
360 * @param max The minimum number of tokens between the elements
361 * of the sequence.
362 * @param exclusion Boolean value indicating, the distance constraint
363 * has to fail.
364 * @return The {@link SpanSequenceQueryWrapper} object for chaining.
365 * @see DistanceConstraint
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000366 */
Nils Diewald8c543432014-02-27 18:25:38 +0000367 public SpanSequenceQueryWrapper withConstraint (int min, int max, boolean exclusion) {
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000368 if (this.constraints == null)
369 this.constraints = new ArrayList<DistanceConstraint>(1);
370 this.constraints.add(new DistanceConstraint(min, max, this.isInOrder, exclusion));
371 return this;
Nils Diewaldd7cb0eb2014-02-12 23:06:10 +0000372 };
373
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000374
375 /**
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000376 * Add a sequence constraint (aka distance constraint)
377 * to the sequence based on a certain unit.
378 * The unit has to be a valid {@link SpanElementQuery} term
379 * or <tt>w</tt> for tokens.
380 *
381 * Multiple constraints are supported.
382 *
383 * A minimum value of zero means, there may be an overlap,
384 * a minimum value of 1 means, there is no token between the spans.
385 * It's weird - we know and dislike that. That's why we have to say:
386 *
387 * <strong>Warning!</strong> Sequence constraints are experimental and
388 * may (hopefully) change in future versions!
389 *
390 * @param min The minimum number of tokens between the elements
391 * of the sequence.
392 * @param max The minimum number of tokens between the elements
393 * of the sequence.
394 * @param unit Unit for distance - will be evaluated to a {@link SpanElementQuery}.
395 * @return The {@link SpanSequenceQueryWrapper} object for chaining.
396 * @see DistanceConstraint
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000397 */
Nils Diewald164f8be2014-02-13 02:43:16 +0000398 public SpanSequenceQueryWrapper withConstraint (int min, int max, String unit) {
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000399 return this.withConstraint(min, max, unit, false);
Nils Diewald8c543432014-02-27 18:25:38 +0000400 };
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000401
Nils Diewald8c543432014-02-27 18:25:38 +0000402
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000403
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000404 /**
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000405 * Add a sequence constraint (aka distance constraint)
406 * to the sequence based on a certain unit and with an
407 * exclusion constraint, meaning the constraint is fine
408 * in case the operands are <em>not</em> within the distance.
409 * The unit has to be a valid {@link SpanElementQuery} term
410 * or <tt>w</tt> for tokens.
411 *
412 * Multiple constraints are supported.
413 *
414 * A minimum value of zero means, there may be an overlap,
415 * a minimum value of 1 means, there is no token between the spans.
416 * It's weird - we know and dislike that. That's why we have to say:
417 *
418 * <strong>Warning!</strong> Sequence constraints are experimental and
419 * may (hopefully) change in future versions!
420 *
421 * @param min The minimum number of tokens between the elements
422 * of the sequence.
423 * @param max The minimum number of tokens between the elements
424 * of the sequence.
425 * @param unit Unit for distance - will be evaluated to a {@link SpanElementQuery}.
426 * @param exclusion Boolean value indicating, the distance constraint
427 * has to fail.
428 * @return The {@link SpanSequenceQueryWrapper} object for chaining.
429 * @see DistanceConstraint
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000430 */
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000431 public SpanSequenceQueryWrapper withConstraint
432 (int min, int max, String unit, boolean exclusion) {
Nils Diewald8db8f922014-10-24 17:43:13 +0000433
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000434 // Word unit
435 if (unit.equals("w")) {
436 if (this.constraints == null)
437 this.constraints = new ArrayList<DistanceConstraint>(1);
438 this.constraints.add(new DistanceConstraint(min, max, isInOrder, exclusion));
439 return this;
440 };
Nils Diewald8db8f922014-10-24 17:43:13 +0000441
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000442 // Element unit (sentence or paragraph)
443 return this.withConstraint(
444 min, max, new SpanElementQueryWrapper(this.field, unit), exclusion
445 );
Nils Diewaldd7cb0eb2014-02-12 23:06:10 +0000446 };
447
Nils Diewald8db8f922014-10-24 17:43:13 +0000448
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000449 /**
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000450 * Add a sequence constraint (aka distance constraint)
451 * to the sequence based on a certain unit and with an
452 * exclusion constraint, meaning the constraint is fine
453 * in case the operands are <em>not</em> within the distance.
454 *
455 * Multiple constraints are supported.
456 *
457 * A minimum value of zero means, there may be an overlap,
458 * a minimum value of 1 means, there is no token between the spans.
459 * It's weird - we know and dislike that. That's why we have to say:
460 *
461 * <strong>Warning!</strong> Sequence constraints are experimental and
462 * may (hopefully) change in future versions!
463 *
464 * @param min The minimum number of tokens between the elements
465 * of the sequence.
466 * @param max The minimum number of tokens between the elements
467 * of the sequence.
468 * @param unit A {@link SpanElementQueryWrapper} as the unit for distance.
469 * @param exclusion Boolean value indicating, the distance constraint
470 * has to fail.
471 * @return The {@link SpanSequenceQueryWrapper} object for chaining.
472 * @see DistanceConstraint
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000473 */
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000474 public SpanSequenceQueryWrapper withConstraint
475 (int min, int max, SpanElementQueryWrapper unit, boolean exclusion) {
476 if (this.constraints == null)
477 this.constraints = new ArrayList<DistanceConstraint>(1);
478
479 // Element unit (sentence or paragraph)
480 // Todo: This should possibly be evaluated to a query later on!
481 try {
482 this.constraints.add(
483 new DistanceConstraint(
Nils Diewaldb9dd4132015-02-16 16:32:41 +0000484 (SpanElementQuery) unit.retrieveNode(this.retrieveNode).toQuery(),
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000485 min,
486 max,
487 isInOrder,
488 exclusion
489 )
490 );
491 }
492 catch (QueryException qe) {
493 this.constraintException = qe;
494 };
495 return this;
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000496 };
497
Nils Diewald8db8f922014-10-24 17:43:13 +0000498
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000499 /**
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000500 * Check if the sequence has to be in order.
501 *
502 * @return <tt>true</tt> in case the sequence
503 * has to be in order and <tt>false</tt>
504 * in case the order is not relevant.
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000505 */
506 public boolean isInOrder () {
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000507 return this.isInOrder;
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000508 };
509
Nils Diewald8db8f922014-10-24 17:43:13 +0000510
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000511 /**
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000512 * Set the boolean value indicating if the sequence
513 * has to be in order.
514 *
515 * @param order <tt>true</tt> in case the sequence
516 * has to be in order and <tt>false</tt>
517 * in case the order is not relevant.
518 */
519 public void setInOrder (boolean order) {
520 this.isInOrder = order;
521 };
522
523
524 /**
525 * Check if the sequence has constraints.
526 *
527 * @return <tt>true</tt> in case the sequence
528 * has any constraints and <tt>false</tt>
529 * in case it is a simple next query.
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000530 */
531 public boolean hasConstraints () {
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000532 if (this.constraints == null)
533 return false;
Nils Diewald8db8f922014-10-24 17:43:13 +0000534
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000535 if (this.constraints.size() <= 0)
536 return false;
537
538 // The constraint is in fact a next query,
539 // that will be optimized away later on
540 if (this.constraints.size() == 1) {
541 DistanceConstraint dc = this.constraints.get(0);
542 if (dc.getUnit().equals("w") &&
543 dc.getMinDistance() == 1 &&
544 dc.getMaxDistance() == 1) {
545 return false;
546 };
547 };
Nils Diewald8db8f922014-10-24 17:43:13 +0000548
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000549 return true;
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000550 };
551
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000552
553 public boolean isEmpty () {
554 if (this.segments.size() == 1)
555 return this.segments.get(0).isEmpty();
556
557 if (!this.isSolved)
558 _solveProblematicSequence();
559 return super.isEmpty();
560 };
561
562
563 public boolean isOptional () {
564 if (this.segments.size() == 1)
565 return this.segments.get(0).isOptional();
566 if (!this.isSolved)
567 _solveProblematicSequence();
568 return super.isOptional();
569 };
570
571 public boolean isNegative () {
572 if (this.segments.size() == 1)
573 return this.segments.get(0).isNegative();
574 if (!this.isSolved)
575 _solveProblematicSequence();
576 return super.isNegative();
577 };
578
579 public boolean isExtendedToTheRight () {
580 if (!this.isSolved)
581 _solveProblematicSequence();
582 return this.isExtendedToTheRight;
583 };
584
585
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000586 /**
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000587 * Serialize the wrapped sequence to a {@link SpanQuery} object.
588 *
589 * @return A {@link SpanQuery} object.
590 * @throws QueryException
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000591 */
592 public SpanQuery toQuery () throws QueryException {
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000593
594 // There was a serialization failure not yet reported
595 if (this.constraintException != null)
596 throw constraintException;
597
Nils Diewald6409a922015-01-29 20:50:42 +0000598 int size = this.segments.size();
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000599
Nils Diewald6409a922015-01-29 20:50:42 +0000600 // Nothing to do
601 if (size == 0 || this.isNull())
602 return (SpanQuery) null;
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000603
Nils Diewald6409a922015-01-29 20:50:42 +0000604 // No real sequence - only one element
605 if (size == 1) {
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000606
Nils Diewald6409a922015-01-29 20:50:42 +0000607 // But the element may be expanded
608 if (this.segments.get(0).isExtended() &&
609 (this.hasConstraints() || !this.isInOrder())) {
610 throw new QueryException(613, limitationError);
611 };
Nils Diewald8db8f922014-10-24 17:43:13 +0000612
Nils Diewald6409a922015-01-29 20:50:42 +0000613 // Unproblematic single query
614 if (this.segments.get(0).maybeAnchor())
Nils Diewaldb9dd4132015-02-16 16:32:41 +0000615 return (SpanQuery) this.segments.get(0).retrieveNode(this.retrieveNode).toQuery();
Nils Diewald8db8f922014-10-24 17:43:13 +0000616
Nils Diewald6409a922015-01-29 20:50:42 +0000617 if (this.segments.get(0).isEmpty())
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000618 throw new QueryException(
619 613, "Sequence is not allowed to be empty"
620 );
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000621
Nils Diewald6409a922015-01-29 20:50:42 +0000622 if (this.segments.get(0).isOptional())
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000623 throw new QueryException(
624 613, "Sequence is not allowed to be optional"
625 );
Nils Diewaldf399a672013-11-18 17:55:22 +0000626
Nils Diewald6409a922015-01-29 20:50:42 +0000627 if (this.segments.get(0).isNegative())
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000628 throw new QueryException(
629 613, "Sequence is not allowed to be negative"
630 );
Nils Diewald6409a922015-01-29 20:50:42 +0000631 };
Nils Diewald8db8f922014-10-24 17:43:13 +0000632
Nils Diewald6409a922015-01-29 20:50:42 +0000633 if (!this.isSolved) {
634 if (!_solveProblematicSequence()) {
635 if (this.segments.get(0).maybeExtension()) {
636 throw new QueryException(
637 613,
638 "Sequence contains unresolvable " +
639 "empty, optional, or negative segments"
640 );
641 };
642 };
643 };
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000644
Nils Diewald6409a922015-01-29 20:50:42 +0000645 // The element may be expanded
646 if (this.segments.size() == 1 &&
647 this.segments.get(0).isExtended() &&
648 (this.hasConstraints() || !this.isInOrder())) {
649 throw new QueryException(613, limitationError);
650 };
Nils Diewaldf399a672013-11-18 17:55:22 +0000651
Nils Diewald6409a922015-01-29 20:50:42 +0000652 // Create the initial query
653 SpanQuery query = null;// = this.segments.get(0).toQuery();
654 int i = 0;
655 while (query == null && i < this.segments.size()) {
Nils Diewaldb9dd4132015-02-16 16:32:41 +0000656 query = this.segments.get(i).retrieveNode(this.retrieveNode).toQuery();
Nils Diewald6409a922015-01-29 20:50:42 +0000657 i++;
658 };
Nils Diewaldd7cb0eb2014-02-12 23:06:10 +0000659
Nils Diewald6409a922015-01-29 20:50:42 +0000660 if (query == null)
661 return (SpanQuery) null;
Nils Diewald164f8be2014-02-13 02:43:16 +0000662
Nils Diewald6409a922015-01-29 20:50:42 +0000663 // NextQueries:
664 if (!this.hasConstraints() && this.isInOrder()) {
665 for (; i < this.segments.size(); i++) {
Nils Diewald8db8f922014-10-24 17:43:13 +0000666
Nils Diewaldb9dd4132015-02-16 16:32:41 +0000667 SpanQuery second = this.segments.get(i).retrieveNode(this.retrieveNode).toQuery();
Nils Diewald6409a922015-01-29 20:50:42 +0000668 if (second == null)
669 continue;
Nils Diewald8db8f922014-10-24 17:43:13 +0000670
Nils Diewald6409a922015-01-29 20:50:42 +0000671 query = new SpanNextQuery(
672 query,
673 second
674 );
675 };
676 return (SpanQuery) query;
677 };
678
679 // DistanceQueries
680 if (this.constraints.size() == 1) {
681 DistanceConstraint constraint = this.constraints.get(0);
Nils Diewald164f8be2014-02-13 02:43:16 +0000682
Nils Diewald6409a922015-01-29 20:50:42 +0000683 // Create spanElementDistance query
684 if (!constraint.getUnit().equals("w")) {
685 for (i = 1; i < this.segments.size(); i++) {
Nils Diewald8db8f922014-10-24 17:43:13 +0000686
Nils Diewald6409a922015-01-29 20:50:42 +0000687 // No support for extended spans in constraints
688 if (this.segments.get(i).isExtended())
689 throw new QueryException(613, limitationError);
Nils Diewald8db8f922014-10-24 17:43:13 +0000690
Nils Diewaldb9dd4132015-02-16 16:32:41 +0000691 SpanQuery sq = (SpanQuery) this.segments.get(i).retrieveNode(this.retrieveNode).toQuery();
Nils Diewald6409a922015-01-29 20:50:42 +0000692 if (sq == null) continue;
Nils Diewald164f8be2014-02-13 02:43:16 +0000693
Nils Diewald6409a922015-01-29 20:50:42 +0000694 SpanDistanceQuery sdquery = new SpanDistanceQuery(
695 query,
696 sq,
697 constraint,
698 true
699 );
700 query = (SpanQuery) sdquery;
701 };
702 }
Nils Diewaldd7cb0eb2014-02-12 23:06:10 +0000703
Nils Diewald6409a922015-01-29 20:50:42 +0000704 // Create spanDistance query
705 else {
706 for (i = 1; i < this.segments.size(); i++) {
Nils Diewald8db8f922014-10-24 17:43:13 +0000707
Nils Diewald6409a922015-01-29 20:50:42 +0000708 // No support for extended spans in constraints
709 if (this.segments.get(i).isExtended())
710 throw new QueryException(613, limitationError);
Nils Diewald8db8f922014-10-24 17:43:13 +0000711
Nils Diewaldb9dd4132015-02-16 16:32:41 +0000712 SpanQuery sq = (SpanQuery) this.segments.get(i).retrieveNode(this.retrieveNode).toQuery();
Nils Diewald6409a922015-01-29 20:50:42 +0000713 if (sq == null) continue;
714
715 SpanDistanceQuery sdquery = new SpanDistanceQuery(
716 query,
717 sq,
718 constraint,
719 true
720 );
721 query = (SpanQuery) sdquery;
722 };
723 };
724
725 return (SpanQuery) query;
726 };
727
728 // MultipleDistanceQueries
729 for (i = 1; i < this.segments.size(); i++) {
730
731 // No support for extended spans in constraints
732 if (this.segments.get(i).isExtended())
733 throw new QueryException(613, limitationError);
734
Nils Diewaldb9dd4132015-02-16 16:32:41 +0000735 SpanQuery sq = (SpanQuery) this.segments.get(i).retrieveNode(this.retrieveNode).toQuery();
Nils Diewald6409a922015-01-29 20:50:42 +0000736 if (sq == null) continue;
737
738 query = new SpanMultipleDistanceQuery(
739 query,
740 sq,
741 this.constraints,
742 isInOrder,
743 true
744 );
745 };
746 return (SpanQuery) query;
Nils Diewaldd7cb0eb2014-02-12 23:06:10 +0000747 };
748
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000749
750
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000751 /*
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000752 Check if there are problematic segments in the sequence
753 (either negative, optional or empty) and deal with them
754 (make optional segments to or-queries and negative and empty
755 segments to extensions).
756 This has to be done as long as there are problematic segments
757 In the queries.
758
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000759 While there is a segment isNegative() or isOptional() or isEmpty() do
760 - look for an anchor next to it
761 - merge the problematic segment with the anchor
762 - go on
763 */
Nils Diewald8db8f922014-10-24 17:43:13 +0000764 private boolean _solveProblematicSequence () {
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000765 int size = this.segments.size();
766 // Check if there is a problematic segment
767 SpanQueryWrapper underScrutiny;
768 boolean noRemainingProblem = true;
769 int i = 0;
Nils Diewald8db8f922014-10-24 17:43:13 +0000770
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000771 if (DEBUG)
772 log.trace("Try to solve a query of {} segments", size);
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000773
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000774 // Iterate over all segments
775 for (; i < size;) {
776 underScrutiny = this.segments.get(i);
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000777
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000778 // Check if there is a problem with the current segment
779 if (!underScrutiny.maybeAnchor()) {
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000780
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000781 if (DEBUG)
782 log.trace("segment {} is problematic", i);
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000783
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000784 // [problem][anchor]
785 if (i < (size-1) && this.segments.get(i+1).maybeAnchor()) {
786 if (DEBUG)
787 log.trace("Situation is [problem][anchor]");
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000788
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000789 // Insert the solution
790 try {
791 this.segments.set(
792 i+1,
793 _merge(this.segments.get(i+1), underScrutiny, false)
794 );
795 }
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000796
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000797 // An error occurred while solving the problem
798 catch (QueryException e) {
799 return false;
800 };
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000801
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000802 // Remove the problem
803 this.segments.remove(i);
804 size--;
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000805
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000806 if (DEBUG)
807 log.trace("Remove segment {} - now size {}", i, size);
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000808
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000809 // Restart checking
810 i = 0;
811 }
Nils Diewaldb84e7272014-11-07 01:27:38 +0000812
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000813 // [anchor][problem]
814 else if (i >= 1 && this.segments.get(i-1).maybeAnchor()) {
815 if (DEBUG)
816 log.trace("Situation is [anchor][problem]");
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000817
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000818 // Insert the solution
819 try {
820 this.segments.set(
821 i-1,
822 _merge(this.segments.get(i-1), underScrutiny, true)
823 );
824 }
825 catch (QueryException e) {
826 return false;
827 };
Nils Diewaldb84e7272014-11-07 01:27:38 +0000828
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000829 // Remove the problem
830 this.segments.remove(i);
831 size--;
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000832
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000833 if (DEBUG)
834 log.trace("Remove segment {} - now size {}", i, size);
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000835
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000836 // Restart checking
837 i = 0;
838 }
839 // [problem][problem]
840 else {
841 if (DEBUG)
842 log.trace("Situation is [problem][problem]");
843 noRemainingProblem = false;
844 i++;
845 };
846 }
847 else {
848 if (DEBUG)
849 log.trace("segment {} can be an anchor", i);
850 i++;
851 };
852 };
Nils Diewaldb84e7272014-11-07 01:27:38 +0000853
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000854 // There is still a remaining problem
855 if (!noRemainingProblem) {
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000856
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000857 // The size has changed - retry!
858 if (size != this.segments.size())
859 return _solveProblematicSequence();
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000860
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000861 this.isSolved = true;
862 return true;
863 };
Nils Diewald8db8f922014-10-24 17:43:13 +0000864
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000865 this.isSolved = true;
866 return false;
Nils Diewaldd7cb0eb2014-02-12 23:06:10 +0000867 };
868
Nils Diewald164f8be2014-02-13 02:43:16 +0000869
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000870 // Todo: Deal with negative and optional!
871 // [base=der][base!=Baum]?
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000872 private SpanQueryWrapper _merge (SpanQueryWrapper anchor,
873 SpanQueryWrapper problem,
874 boolean mergeLeft) throws QueryException {
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000875
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000876 // Extend to the right - merge to the left
877 int direction = mergeLeft ? 1 : -1;
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000878
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000879 if (DEBUG)
880 log.trace("Will merge two spans to {}",
881 mergeLeft ? "left" : "right");
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000882
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000883 // Make empty extension to anchor
884 if (problem.isEmpty()) {
885 SpanQuery query;
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000886
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000887 if (DEBUG)
888 log.trace("Problem is empty with class {}",
889 problem.getClassNumber());
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000890
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000891 query = new SpanExpansionQuery(
Nils Diewaldb9dd4132015-02-16 16:32:41 +0000892 anchor.retrieveNode(this.retrieveNode).toQuery(),
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000893 problem.getMin(),
894 problem.getMax(),
895 direction,
896 problem.hasClass() ? problem.getClassNumber() : (byte) 0,
897 true
898 );
899 return new SpanSimpleQueryWrapper(query).isExtended(true);
900 }
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000901
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000902 // make negative extension to anchor
903 else if (problem.isNegative()) {
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000904
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000905 SpanQuery query;
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000906
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000907 if (DEBUG)
908 log.trace("Problem is negative with class {}",
909 problem.getClassNumber());
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000910
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000911 query = new SpanExpansionQuery(
Nils Diewaldb9dd4132015-02-16 16:32:41 +0000912 anchor.retrieveNode(this.retrieveNode).toQuery(),
913 problem.retrieveNode(this.retrieveNode).toQuery(),
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000914 problem.getMin(),
915 problem.getMax(),
916 direction,
917 problem.hasClass() ? problem.getClassNumber() : (byte) 0,
918 true
919 );
920 return new SpanSimpleQueryWrapper(query).isExtended(true);
921 };
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000922
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000923 if (DEBUG)
924 log.trace("Problem is optional");
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000925
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000926 // [base=der][base=baum]?
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000927
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000928 // [base=der]
929 SpanAlterQueryWrapper saqw =
930 new SpanAlterQueryWrapper(this.field, anchor);
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000931
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000932 // [base=der]
933 SpanSequenceQueryWrapper ssqw =
934 new SpanSequenceQueryWrapper(this.field, anchor);
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000935
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000936 // [base=der][base=baum]
937 if (mergeLeft)
Nils Diewaldb9dd4132015-02-16 16:32:41 +0000938 ssqw.append(new SpanSimpleQueryWrapper(problem.retrieveNode(this.retrieveNode).toQuery()));
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000939 // [base=baum][base=der]
940 else
Nils Diewaldb9dd4132015-02-16 16:32:41 +0000941 ssqw.prepend(new SpanSimpleQueryWrapper(problem.retrieveNode(this.retrieveNode).toQuery()));
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000942
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000943 saqw.or(ssqw);
Nils Diewaldbe5943e2014-10-21 19:35:34 +0000944
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000945 return (SpanQueryWrapper) saqw;
Nils Diewald8db8f922014-10-24 17:43:13 +0000946 };
Nils Diewaldf399a672013-11-18 17:55:22 +0000947};