blob: 31b8f26784553711801038b0099698ae21e5e3fc [file] [log] [blame]
Eliza Margarethae18d62e2014-02-11 11:30:48 +00001package de.ids_mannheim.korap.query;
2
3import java.io.IOException;
4import java.util.List;
5import java.util.Map;
6
7import org.apache.lucene.index.AtomicReaderContext;
8import org.apache.lucene.index.Term;
9import org.apache.lucene.index.TermContext;
10import org.apache.lucene.search.spans.SpanQuery;
11import org.apache.lucene.search.spans.Spans;
12import org.apache.lucene.util.Bits;
Eliza Margaretha609fcc62014-02-13 14:10:20 +000013import org.apache.lucene.util.ToStringUtils;
Eliza Margarethae18d62e2014-02-11 11:30:48 +000014
15import de.ids_mannheim.korap.query.spans.MultipleDistanceSpans;
16
Eliza Margarethadffd0592015-01-15 18:24:39 +000017/**
18 * SpanMultipleDistanceQuery matches two spans with respect to a list of
19 * distance constraints. No repetition of constraints of the same unit type
20 * (e.g. word, sentence, paragraph) is allowed. For example, there must only
21 * exactly one constraint for word/token-based distance. A SpanDistanceQuery is
22 * created for each constraint.<br />
23 * <br />
24 * Examples:
25 * <ul>
26 *
27 * <li>
28 * Search two terms x and y which are separated by minimum two and maximum three
29 * other words within the same sentence. The order of x and y does not matter.
30 *
31 * <pre>
32 * List&lt;DistanceConstraint&gt; constraints = new ArrayList&lt;DistanceConstraint&gt;();
33 * constraints.add(new DistanceConstraint(2, 3, false, false));
34 * constraints.add(DistanceConstraint(new SpanElementQuery(&quot;tokens&quot;, &quot;s&quot;), 0, 0,
35 * false, false));
36 *
37 * SpanMultipleDistanceQuery mdq = SpanMultipleDistanceQuery(x, y, constraints,
38 * false, true);
39 * </pre>
40 *
41 * </li>
42 *
43 * <li>
44 * Search term x which do <em>not</em> occur with term y in minimum two and
45 * maximum three other words and <em>not</em> in the same sentence. X must
46 * precede y.
47 *
48 * <pre>
49 * List&lt;DistanceConstraint&gt; constraints = new ArrayList&lt;DistanceConstraint&gt;();
50 * constraints.add(new DistanceConstraint(2, 3, false, true));
51 * constraints.add(DistanceConstraint(new SpanElementQuery(&quot;tokens&quot;, &quot;s&quot;), 0, 0,
52 * false, true));
53 *
54 * SpanMultipleDistanceQuery mdq = SpanMultipleDistanceQuery(x, y, constraints,
55 * true, true);
56 * </pre>
57 *
58 * </li>
59 * </ul>
60 *
61 * @author margaretha
Eliza Margarethae18d62e2014-02-11 11:30:48 +000062 * */
Eliza Margarethadffd0592015-01-15 18:24:39 +000063public class SpanMultipleDistanceQuery extends SimpleSpanQuery {
Eliza Margarethae18d62e2014-02-11 11:30:48 +000064
Eliza Margarethadffd0592015-01-15 18:24:39 +000065 private List<DistanceConstraint> constraints;
66 private boolean isOrdered;
67 private String spanName;
68
69 /**
70 * Constructs a SpanMultipleDistanceQuery for the two given SpanQueries.
71 *
72 * @param firstClause the first SpanQuery
73 * @param secondClause the second SpanQuery
74 * @param constraints the list of distance constraints
75 * @param isOrdered a boolean representing the value <code>true</code>, if
76 * the firstspans must occur before the secondspans, otherwise
77 * <code>false</code>.
78 * @param collectPayloads a boolean flag representing the value
79 * <code>true</code> if payloads are to be collected, otherwise
80 * <code>false</code>.
81 */
82 public SpanMultipleDistanceQuery(SpanQuery firstClause,
83 SpanQuery secondClause, List<DistanceConstraint> constraints,
84 boolean isOrdered, boolean collectPayloads) {
85 super(firstClause, secondClause, collectPayloads);
86 this.constraints = constraints;
87 this.isOrdered = isOrdered;
88 spanName = "spanMultipleDistance";
Eliza Margaretha609fcc62014-02-13 14:10:20 +000089 }
Eliza Margarethae18d62e2014-02-11 11:30:48 +000090
Eliza Margarethadffd0592015-01-15 18:24:39 +000091 @Override
92 public SpanMultipleDistanceQuery clone() {
93 SpanMultipleDistanceQuery query = new SpanMultipleDistanceQuery(
94 (SpanQuery) firstClause.clone(),
95 (SpanQuery) secondClause.clone(), this.constraints,
96 this.isOrdered, collectPayloads);
Eliza Margarethae18d62e2014-02-11 11:30:48 +000097
Eliza Margarethadffd0592015-01-15 18:24:39 +000098 query.setBoost(getBoost());
99 return query;
100 }
101
102 @Override
103 public String toString(String field) {
104 StringBuilder sb = new StringBuilder();
105 sb.append(this.spanName);
106 sb.append("(");
107 sb.append(firstClause.toString(field));
108 sb.append(", ");
109 sb.append(secondClause.toString(field));
110 sb.append(", ");
111 sb.append("[");
112
113 DistanceConstraint c;
114 int size = constraints.size();
115 for (int i = 0; i < size; i++) {
116 c = constraints.get(i);
117 sb.append("(");
118 sb.append(c.getUnit());
119 sb.append("[");
120 sb.append(c.getMinDistance());
121 sb.append(":");
122 sb.append(c.getMaxDistance());
123 sb.append("], ");
124 sb.append(c.isOrdered() ? "ordered, " : "notOrdered, ");
Nils Diewald0cc4f2e2015-01-30 20:13:08 +0000125 sb.append(c.isExclusion() ? "excluded)" : "notExcluded)");
Eliza Margarethadffd0592015-01-15 18:24:39 +0000126 if (i < size - 1)
127 sb.append(", ");
128 }
129 sb.append("])");
130 sb.append(ToStringUtils.boost(getBoost()));
131 return sb.toString();
132 }
133
134 /**
135 * Filters the span matches of each constraint, returning only the matches
136 * meeting all the constraints.
137 *
138 * @return only the span matches meeting all the constraints.
139 * */
140 @Override
141 public Spans getSpans(AtomicReaderContext context, Bits acceptDocs,
142 Map<Term, TermContext> termContexts) throws IOException {
143
144 SpanDistanceQuery sdq, sdq2;
145 Spans ds, ds2;
146 MultipleDistanceSpans mds = null;
147 boolean exclusion;
148
149 sdq = new SpanDistanceQuery(firstClause, secondClause,
150 constraints.get(0), collectPayloads);
151 ds = sdq.getSpans(context, acceptDocs, termContexts);
152
153 for (int i = 1; i < constraints.size(); i++) {
154 sdq2 = new SpanDistanceQuery(firstClause, secondClause,
155 constraints.get(i), collectPayloads);
156 ds2 = sdq2.getSpans(context, acceptDocs, termContexts);
157
158 exclusion = sdq.isExclusion() && sdq2.isExclusion();
159 mds = new MultipleDistanceSpans(this, context, acceptDocs,
160 termContexts, ds, ds2, isOrdered, exclusion);
161 ds = mds;
162 }
163
164 return mds;
165 }
166
167 /**
168 * Returns the list of distance constraints.
169 *
170 * @return the list of distance constraints
171 */
172 public List<DistanceConstraint> getConstraints() {
173 return constraints;
174 }
175
176 /**
177 * Sets the list of distance constraints.
178 *
179 * @param constraints the list of distance constraints
180 */
181 public void setConstraints(List<DistanceConstraint> constraints) {
182 this.constraints = constraints;
183 }
184
Eliza Margarethae18d62e2014-02-11 11:30:48 +0000185}