| Nils Diewald | f399a67 | 2013-11-18 17:55:22 +0000 | [diff] [blame] | 1 | package de.ids_mannheim.korap; |
| 2 | |
| Eliza Margaretha | 221349f | 2015-01-29 17:27:41 +0000 | [diff] [blame] | 3 | import java.io.IOException; |
| Eliza Margaretha | 641b20a | 2015-02-16 17:23:13 +0000 | [diff] [blame] | 4 | import java.util.ArrayList; |
| 5 | import java.util.List; |
| Akron | 738ed00 | 2015-06-18 12:07:50 +0200 | [diff] [blame] | 6 | import java.util.Iterator; |
| Eliza Margaretha | afe9812 | 2015-01-23 17:37:57 +0000 | [diff] [blame] | 7 | |
| Eliza Margaretha | b1a5ed4 | 2015-01-26 10:37:12 +0000 | [diff] [blame] | 8 | import org.slf4j.Logger; |
| 9 | import org.slf4j.LoggerFactory; |
| 10 | |
| Eliza Margaretha | 221349f | 2015-01-29 17:27:41 +0000 | [diff] [blame] | 11 | import com.fasterxml.jackson.databind.JsonNode; |
| 12 | import com.fasterxml.jackson.databind.ObjectMapper; |
| margaretha | 144983d | 2015-05-07 11:52:17 +0200 | [diff] [blame] | 13 | import com.fasterxml.jackson.databind.node.ArrayNode; |
| 14 | import com.fasterxml.jackson.databind.node.ObjectNode; |
| Eliza Margaretha | 221349f | 2015-01-29 17:27:41 +0000 | [diff] [blame] | 15 | |
| Nils Diewald | 8904c1d | 2015-02-26 16:13:18 +0000 | [diff] [blame] | 16 | import de.ids_mannheim.korap.query.QueryBuilder; |
| margaretha | 5c26de4 | 2015-04-14 12:47:58 +0200 | [diff] [blame] | 17 | import de.ids_mannheim.korap.query.SpanWithinQuery; |
| 18 | import de.ids_mannheim.korap.query.wrap.SpanAlterQueryWrapper; |
| 19 | import de.ids_mannheim.korap.query.wrap.SpanAttributeQueryWrapper; |
| 20 | import de.ids_mannheim.korap.query.wrap.SpanClassQueryWrapper; |
| 21 | import de.ids_mannheim.korap.query.wrap.SpanFocusQueryWrapper; |
| 22 | import de.ids_mannheim.korap.query.wrap.SpanQueryWrapper; |
| margaretha | 144983d | 2015-05-07 11:52:17 +0200 | [diff] [blame] | 23 | import de.ids_mannheim.korap.query.wrap.SpanReferenceQueryWrapper; |
| margaretha | 5c26de4 | 2015-04-14 12:47:58 +0200 | [diff] [blame] | 24 | import de.ids_mannheim.korap.query.wrap.SpanRegexQueryWrapper; |
| 25 | import de.ids_mannheim.korap.query.wrap.SpanRelationWrapper; |
| 26 | import de.ids_mannheim.korap.query.wrap.SpanRepetitionQueryWrapper; |
| 27 | import de.ids_mannheim.korap.query.wrap.SpanSegmentQueryWrapper; |
| 28 | import de.ids_mannheim.korap.query.wrap.SpanSequenceQueryWrapper; |
| 29 | import de.ids_mannheim.korap.query.wrap.SpanSimpleQueryWrapper; |
| 30 | import de.ids_mannheim.korap.query.wrap.SpanSubspanQueryWrapper; |
| 31 | import de.ids_mannheim.korap.query.wrap.SpanWithAttributeQueryWrapper; |
| 32 | import de.ids_mannheim.korap.query.wrap.SpanWithinQueryWrapper; |
| Eliza Margaretha | 221349f | 2015-01-29 17:27:41 +0000 | [diff] [blame] | 33 | import de.ids_mannheim.korap.response.Notifications; |
| 34 | import de.ids_mannheim.korap.util.QueryException; |
| 35 | |
| Nils Diewald | f399a67 | 2013-11-18 17:55:22 +0000 | [diff] [blame] | 36 | /** |
| Nils Diewald | 21914ff | 2015-02-28 02:09:47 +0000 | [diff] [blame] | 37 | * <p> |
| Nils Diewald | 8904c1d | 2015-02-26 16:13:18 +0000 | [diff] [blame] | 38 | * KrillQuery provides deserialization methods |
| 39 | * for KoralQuery query objects. |
| Nils Diewald | 21914ff | 2015-02-28 02:09:47 +0000 | [diff] [blame] | 40 | * </p> |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 41 | * |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 42 | * <blockquote><pre> |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 43 | * // Create or receive a KoralQuery JSON string |
| 44 | * String koral = "{\"@type\":"koral:group", ... }"; |
| 45 | * |
| 46 | * SpanQueryWrapper sqw = new |
| Akron | 626dd9f | 2016-06-08 10:08:55 +0200 | [diff] [blame^] | 47 | * KrillQuery("tokens").fromKoral("{... JsonString ...}"); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 48 | * </pre></blockquote> |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 49 | * |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 50 | * @author diewald |
| Nils Diewald | f399a67 | 2013-11-18 17:55:22 +0000 | [diff] [blame] | 51 | */ |
| Nils Diewald | cec40f9 | 2015-02-19 22:20:02 +0000 | [diff] [blame] | 52 | /* |
| Nils Diewald | 6535c52 | 2015-02-26 17:45:24 +0000 | [diff] [blame] | 53 | TODO: Merge this with SpanQueryWrapper |
| Nils Diewald | f5ab4b2 | 2015-02-25 20:55:16 +0000 | [diff] [blame] | 54 | |
| Nils Diewald | 6535c52 | 2015-02-26 17:45:24 +0000 | [diff] [blame] | 55 | TODO: Use full-blown jsonld processor |
| 56 | |
| 57 | TODO: All queries with a final right expansion |
| Nils Diewald | cec40f9 | 2015-02-19 22:20:02 +0000 | [diff] [blame] | 58 | e.g. der alte [] |
| 59 | should be wrapped in a contains(<base/s=t>) to ensure |
| 60 | they are not outside the text. |
| Nils Diewald | 21914ff | 2015-02-28 02:09:47 +0000 | [diff] [blame] | 61 | |
| Nils Diewald | cec40f9 | 2015-02-19 22:20:02 +0000 | [diff] [blame] | 62 | TODO: Create Pre-filter while preparing a Query. |
| 63 | The pre-filter will contain a boolena query with all |
| 64 | necessary terms, supporting boolean OR, ignoring |
| 65 | negation terms (and negation subqueries), like |
| 66 | [base=Der]([base=alte]|[base=junge])[base=Mann & p!=ADJA]![base=war | base=lag] |
| 67 | Search for all documents containing "s:Der" and ("s:alte" or "s:junge") and "s:Mann" |
| 68 | */ |
| Akron | 98b7854 | 2015-08-06 21:43:08 +0200 | [diff] [blame] | 69 | public final class KrillQuery extends Notifications { |
| Nils Diewald | 8904c1d | 2015-02-26 16:13:18 +0000 | [diff] [blame] | 70 | private QueryBuilder builder; |
| Nils Diewald | 21914ff | 2015-02-28 02:09:47 +0000 | [diff] [blame] | 71 | private String field; |
| Nils Diewald | bbd39a5 | 2015-02-23 19:56:57 +0000 | [diff] [blame] | 72 | private JsonNode json; |
| Nils Diewald | f399a67 | 2013-11-18 17:55:22 +0000 | [diff] [blame] | 73 | |
| 74 | // Logger |
| Nils Diewald | 0339d46 | 2015-02-26 14:53:56 +0000 | [diff] [blame] | 75 | private final static Logger log = LoggerFactory.getLogger(KrillQuery.class); |
| Nils Diewald | f399a67 | 2013-11-18 17:55:22 +0000 | [diff] [blame] | 76 | |
| Nils Diewald | 8c54343 | 2014-02-27 18:25:38 +0000 | [diff] [blame] | 77 | // This advices the java compiler to ignore all loggings |
| 78 | public static final boolean DEBUG = false; |
| 79 | |
| Nils Diewald | f5ab4b2 | 2015-02-25 20:55:16 +0000 | [diff] [blame] | 80 | // <legacy> |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 81 | public static final byte OVERLAP = SpanWithinQuery.OVERLAP, |
| 82 | REAL_OVERLAP = SpanWithinQuery.REAL_OVERLAP, |
| 83 | WITHIN = SpanWithinQuery.WITHIN, |
| 84 | REAL_WITHIN = SpanWithinQuery.REAL_WITHIN, |
| 85 | ENDSWITH = SpanWithinQuery.ENDSWITH, |
| 86 | STARTSWITH = SpanWithinQuery.STARTSWITH, |
| 87 | MATCH = SpanWithinQuery.MATCH; |
| Nils Diewald | f5ab4b2 | 2015-02-25 20:55:16 +0000 | [diff] [blame] | 88 | // </legacy> |
| Nils Diewald | 6802acd | 2014-03-18 18:29:30 +0000 | [diff] [blame] | 89 | |
| Nils Diewald | 56dc258 | 2014-11-04 21:33:46 +0000 | [diff] [blame] | 90 | private static final int MAX_CLASS_NUM = 255; // 127; |
| Nils Diewald | 8c54343 | 2014-02-27 18:25:38 +0000 | [diff] [blame] | 91 | |
| Nils Diewald | cec40f9 | 2015-02-19 22:20:02 +0000 | [diff] [blame] | 92 | // Private class for koral:boundary objects |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 93 | private class Boundary { |
| 94 | public int min, max; |
| 95 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 96 | |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 97 | // Constructor for boundaries |
| 98 | public Boundary (JsonNode json, int defaultMin, int defaultMax) |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 99 | throws QueryException { |
| 100 | |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 101 | // No @type defined |
| 102 | if (!json.has("@type")) { |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 103 | throw new QueryException(701, |
| 104 | "JSON-LD group has no @type attribute"); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 105 | }; |
| 106 | |
| 107 | // Wrong @type defined |
| Nils Diewald | cec40f9 | 2015-02-19 22:20:02 +0000 | [diff] [blame] | 108 | if (!json.get("@type").asText().equals("koral:boundary")) |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 109 | throw new QueryException(702, "Boundary definition is invalid"); |
| 110 | |
| 111 | // Set min boundary |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 112 | this.min = json.has("min") ? json.get("min").asInt(defaultMin) |
| 113 | : defaultMin; |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 114 | |
| 115 | // Set max boundary |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 116 | this.max = json.has("max") ? json.get("max").asInt(defaultMax) |
| 117 | : defaultMax; |
| 118 | |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 119 | if (DEBUG) |
| Nils Diewald | cec40f9 | 2015-02-19 22:20:02 +0000 | [diff] [blame] | 120 | log.trace("Found koral:boundary with {}:{}", min, max); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 121 | }; |
| 122 | }; |
| 123 | |
| Akron | bb5d173 | 2015-06-22 01:22:40 +0200 | [diff] [blame] | 124 | |
| Nils Diewald | 21914ff | 2015-02-28 02:09:47 +0000 | [diff] [blame] | 125 | /** |
| 126 | * Constructs a new object for query deserialization |
| 127 | * and building. Expects the name of an index field |
| 128 | * to apply the query on (this should normally be |
| 129 | * a token stream field). |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 130 | * |
| 131 | * @param field |
| 132 | * The specific index field for the query. |
| Nils Diewald | 21914ff | 2015-02-28 02:09:47 +0000 | [diff] [blame] | 133 | */ |
| 134 | public KrillQuery (String field) { |
| 135 | this.field = field; |
| 136 | }; |
| 137 | |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 138 | |
| Nils Diewald | 47f62e2 | 2014-07-24 14:51:38 +0000 | [diff] [blame] | 139 | /** |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 140 | * <p>Deserialize JSON-LD query to a {@link SpanQueryWrapper} |
| 141 | * object.</p> |
| 142 | * |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 143 | * <blockquote><pre> |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 144 | * KrillQuery kq = new KrillQuery("tokens"); |
| Akron | 626dd9f | 2016-06-08 10:08:55 +0200 | [diff] [blame^] | 145 | * SpanQueryWrapper sqw = kq.fromKoral( |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 146 | * "{\"@type\" : \"koral:token\","+ |
| 147 | * "\"wrap\" : {" + |
| 148 | * "\"@type\" : \"koral:term\"," + |
| 149 | * "\"foundry\" : \"opennlp\"," + |
| 150 | * "\"key\" : \"tree\"," + |
| 151 | * "\"layer\" : \"orth\"," + |
| 152 | * "\"match\" : \"match:eq\""+ |
| 153 | * "}}" |
| 154 | * ); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 155 | * </pre></blockquote> |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 156 | * |
| 157 | * @param json |
| 158 | * String representing the JSON query string. |
| 159 | * @return {@link SpanQueryWrapper} object. |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 160 | * @throws QueryException |
| Nils Diewald | 47f62e2 | 2014-07-24 14:51:38 +0000 | [diff] [blame] | 161 | */ |
| Akron | 626dd9f | 2016-06-08 10:08:55 +0200 | [diff] [blame^] | 162 | public SpanQueryWrapper fromKoral (String json) throws QueryException { |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 163 | JsonNode jsonN; |
| 164 | try { |
| 165 | // Read Json string |
| Nils Diewald | 8904c1d | 2015-02-26 16:13:18 +0000 | [diff] [blame] | 166 | jsonN = new ObjectMapper().readValue(json, JsonNode.class); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 167 | } |
| Nils Diewald | 47f62e2 | 2014-07-24 14:51:38 +0000 | [diff] [blame] | 168 | |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 169 | // Something went wrong |
| 170 | catch (IOException e) { |
| 171 | String msg = e.getMessage(); |
| 172 | log.warn("Unable to parse JSON: " + msg.split("\n")[0]); |
| 173 | throw new QueryException(621, "Unable to parse JSON"); |
| 174 | }; |
| Nils Diewald | 1455e1e | 2014-08-01 16:12:43 +0000 | [diff] [blame] | 175 | |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 176 | // The query is nested in a parent query |
| 177 | if (!jsonN.has("@type") && jsonN.has("query")) |
| 178 | jsonN = jsonN.get("query"); |
| Nils Diewald | 33fcb5d | 2014-11-07 23:27:03 +0000 | [diff] [blame] | 179 | |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 180 | // Deserialize from node |
| Akron | 626dd9f | 2016-06-08 10:08:55 +0200 | [diff] [blame^] | 181 | return this.fromKoral(jsonN); |
| Nils Diewald | 47f62e2 | 2014-07-24 14:51:38 +0000 | [diff] [blame] | 182 | }; |
| 183 | |
| margaretha | b097bac | 2015-04-15 11:37:02 +0200 | [diff] [blame] | 184 | |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 185 | /** |
| Nils Diewald | 21914ff | 2015-02-28 02:09:47 +0000 | [diff] [blame] | 186 | * <p>Deserialize JSON-LD query as a {@link JsonNode} object |
| 187 | * to a {@link SpanQueryWrapper} object.</p> |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 188 | * |
| 189 | * @param json |
| 190 | * {@link JsonNode} representing the JSON query string. |
| 191 | * @return {@link SpanQueryWrapper} object. |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 192 | * @throws QueryException |
| 193 | */ |
| Nils Diewald | 6d50c1f | 2013-12-04 20:14:08 +0000 | [diff] [blame] | 194 | // TODO: Exception messages are horrible! |
| Nils Diewald | 21914ff | 2015-02-28 02:09:47 +0000 | [diff] [blame] | 195 | // TODO: Use the shortcuts implemented in the builder |
| 196 | // instead of the wrapper constructors |
| Nils Diewald | c86aa48 | 2014-02-12 16:58:05 +0000 | [diff] [blame] | 197 | // TODO: Rename this span context! |
| Akron | 626dd9f | 2016-06-08 10:08:55 +0200 | [diff] [blame^] | 198 | public SpanQueryWrapper fromKoral (JsonNode json) throws QueryException { |
| Akron | d504f21 | 2015-06-20 00:27:54 +0200 | [diff] [blame] | 199 | |
| 200 | // Set this for reserialization - may be changed later on |
| 201 | this.json = json; |
| Akron | 626dd9f | 2016-06-08 10:08:55 +0200 | [diff] [blame^] | 202 | return this._fromKoral(json); |
| Akron | d504f21 | 2015-06-20 00:27:54 +0200 | [diff] [blame] | 203 | }; |
| 204 | |
| 205 | |
| Akron | 626dd9f | 2016-06-08 10:08:55 +0200 | [diff] [blame^] | 206 | private SpanQueryWrapper _fromKoral (JsonNode json) throws QueryException { |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 207 | int number = 0; |
| Nils Diewald | 21914ff | 2015-02-28 02:09:47 +0000 | [diff] [blame] | 208 | |
| 209 | // Only accept @typed objects for the moment |
| 210 | // TODO: Support @context for cosmas:... |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 211 | if (!json.has("@type")) |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 212 | throw new QueryException(701, |
| 213 | "JSON-LD group has no @type attribute"); |
| Nils Diewald | 6d50c1f | 2013-12-04 20:14:08 +0000 | [diff] [blame] | 214 | |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 215 | // Get @type for branching |
| 216 | String type = json.get("@type").asText(); |
| Nils Diewald | 1455e1e | 2014-08-01 16:12:43 +0000 | [diff] [blame] | 217 | |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 218 | switch (type) { |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 219 | case "koral:group": |
| 220 | return this._groupFromJson(json); |
| Nils Diewald | 6d50c1f | 2013-12-04 20:14:08 +0000 | [diff] [blame] | 221 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 222 | case "koral:reference": |
| 223 | if (json.has("operation") |
| 224 | && !json.get("operation").asText() |
| 225 | .equals("operation:focus")) |
| 226 | throw new QueryException(712, "Unknown reference operation"); |
| Nils Diewald | 6d50c1f | 2013-12-04 20:14:08 +0000 | [diff] [blame] | 227 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 228 | if (!json.has("operands")) { |
| 229 | throw new QueryException(766, |
| 230 | "Peripheral references are currently not supported"); |
| 231 | } |
| Nils Diewald | c86aa48 | 2014-02-12 16:58:05 +0000 | [diff] [blame] | 232 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 233 | JsonNode operands = json.get("operands"); |
| Nils Diewald | dc8dc34 | 2014-07-25 13:38:50 +0000 | [diff] [blame] | 234 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 235 | if (!operands.isArray()) |
| 236 | throw new QueryException(704, |
| 237 | "Operation needs operand list"); |
| Nils Diewald | c86aa48 | 2014-02-12 16:58:05 +0000 | [diff] [blame] | 238 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 239 | if (operands.size() == 0) |
| 240 | throw new QueryException(704, |
| 241 | "Operation needs operand list"); |
| Nils Diewald | 164f8be | 2014-02-13 02:43:16 +0000 | [diff] [blame] | 242 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 243 | if (operands.size() != 1) |
| 244 | throw new QueryException(705, |
| 245 | "Number of operands is not acceptable"); |
| Nils Diewald | 164f8be | 2014-02-13 02:43:16 +0000 | [diff] [blame] | 246 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 247 | // Reference based on classes |
| 248 | if (json.has("classRef")) { |
| 249 | if (json.has("classRefOp")) { |
| 250 | throw new QueryException(761, |
| 251 | "Class reference operators are currently not supported"); |
| 252 | }; |
| Nils Diewald | b84e727 | 2014-11-07 01:27:38 +0000 | [diff] [blame] | 253 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 254 | number = json.get("classRef").get(0).asInt(); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 255 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 256 | if (number > MAX_CLASS_NUM) |
| 257 | throw new QueryException(709, |
| 258 | "Valid class numbers exceeded"); |
| 259 | } |
| Nils Diewald | 67331b5 | 2014-11-06 21:16:56 +0000 | [diff] [blame] | 260 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 261 | // Reference based on spans |
| 262 | else if (json.has("spanRef")) { |
| 263 | JsonNode spanRef = json.get("spanRef"); |
| 264 | int length = 0; |
| 265 | int startOffset = 0; |
| 266 | if (!spanRef.isArray() || spanRef.size() == 0) { |
| 267 | throw new QueryException(714, |
| 268 | "Span references expect a start position" |
| 269 | + " and a length parameter"); |
| 270 | }; |
| Nils Diewald | 6409a92 | 2015-01-29 20:50:42 +0000 | [diff] [blame] | 271 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 272 | if (spanRef.size() > 1) |
| 273 | length = spanRef.get(1).asInt(0); |
| Nils Diewald | 6409a92 | 2015-01-29 20:50:42 +0000 | [diff] [blame] | 274 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 275 | startOffset = spanRef.get(0).asInt(0); |
| Nils Diewald | ee4a6b7 | 2014-06-30 18:23:12 +0000 | [diff] [blame] | 276 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 277 | if (DEBUG) |
| 278 | log.trace("Wrap span reference {},{}", startOffset, |
| 279 | length); |
| Nils Diewald | 1455e1e | 2014-08-01 16:12:43 +0000 | [diff] [blame] | 280 | |
| Akron | 626dd9f | 2016-06-08 10:08:55 +0200 | [diff] [blame^] | 281 | SpanQueryWrapper sqw = this._fromKoral(operands.get(0)); |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 282 | SpanSubspanQueryWrapper ssqw = new SpanSubspanQueryWrapper( |
| 283 | sqw, startOffset, length); |
| 284 | return ssqw; |
| Akron | bb5d173 | 2015-06-22 01:22:40 +0200 | [diff] [blame] | 285 | } |
| 286 | ; |
| Nils Diewald | ee4a6b7 | 2014-06-30 18:23:12 +0000 | [diff] [blame] | 287 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 288 | if (DEBUG) |
| 289 | log.trace("Wrap class reference {}", number); |
| Nils Diewald | 92729ce | 2014-10-06 16:00:17 +0000 | [diff] [blame] | 290 | |
| Akron | bb5d173 | 2015-06-22 01:22:40 +0200 | [diff] [blame] | 291 | return new SpanFocusQueryWrapper( |
| Akron | 626dd9f | 2016-06-08 10:08:55 +0200 | [diff] [blame^] | 292 | this._fromKoral(operands.get(0)), number); |
| Nils Diewald | c925b49 | 2013-12-03 23:56:10 +0000 | [diff] [blame] | 293 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 294 | case "koral:token": |
| Akron | c63697c | 2015-06-17 22:32:02 +0200 | [diff] [blame] | 295 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 296 | // The token is empty and should be treated like [] |
| 297 | if (!json.has("wrap")) |
| 298 | return new SpanRepetitionQueryWrapper(); |
| 299 | |
| 300 | // Get wrapped token |
| 301 | return this._segFromJson(json.get("wrap")); |
| 302 | |
| 303 | case "koral:span": |
| Akron | 2ac6e53 | 2015-06-27 18:23:32 +0200 | [diff] [blame] | 304 | if (!json.has("wrap")) |
| 305 | return this._termFromJson(json); |
| 306 | |
| Akron | 907d3d7 | 2015-06-30 11:32:42 +0200 | [diff] [blame] | 307 | // This is an ugly hack |
| 308 | return this._termFromJson(json.get("wrap"), "<>:"); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 309 | }; |
| Nils Diewald | 6d50c1f | 2013-12-04 20:14:08 +0000 | [diff] [blame] | 310 | |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 311 | // Unknown query type |
| 312 | throw new QueryException(713, "Query type is not supported"); |
| 313 | }; |
| 314 | |
| Nils Diewald | 6409a92 | 2015-01-29 20:50:42 +0000 | [diff] [blame] | 315 | |
| Nils Diewald | 8904c1d | 2015-02-26 16:13:18 +0000 | [diff] [blame] | 316 | /** |
| Nils Diewald | 21914ff | 2015-02-28 02:09:47 +0000 | [diff] [blame] | 317 | * <p> |
| Nils Diewald | 8904c1d | 2015-02-26 16:13:18 +0000 | [diff] [blame] | 318 | * Get the associated {@link QueryBuilder} object |
| 319 | * for query building. |
| Nils Diewald | 21914ff | 2015-02-28 02:09:47 +0000 | [diff] [blame] | 320 | * </p> |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 321 | * |
| Nils Diewald | 21914ff | 2015-02-28 02:09:47 +0000 | [diff] [blame] | 322 | * <blockquote><pre> |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 323 | * SpanQueryWrapper query = new |
| 324 | * KrillQuery("tokens").builder().re("mate/p=N.*"); |
| Nils Diewald | 21914ff | 2015-02-28 02:09:47 +0000 | [diff] [blame] | 325 | * </pre></blockquote> |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 326 | * |
| Nils Diewald | 21914ff | 2015-02-28 02:09:47 +0000 | [diff] [blame] | 327 | * @return The {@link QueryBuilder}. |
| Nils Diewald | 8904c1d | 2015-02-26 16:13:18 +0000 | [diff] [blame] | 328 | */ |
| 329 | public QueryBuilder builder () { |
| 330 | if (this.builder == null) |
| 331 | this.builder = new QueryBuilder(this.field); |
| 332 | return this.builder; |
| 333 | }; |
| 334 | |
| 335 | |
| 336 | /** |
| 337 | * Return the associated KoralQuery query object |
| 338 | * as a {@link JsonNode}. This won't work, |
| 339 | * if the object was build using a {@link QueryBuilder}, |
| 340 | * therefore it is limited to mirror a deserialized KoralQuery |
| 341 | * object. |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 342 | * |
| Nils Diewald | 8904c1d | 2015-02-26 16:13:18 +0000 | [diff] [blame] | 343 | * @return The {@link JsonNode} representing the query object |
| 344 | * of a deserialized KoralQuery object. |
| 345 | */ |
| 346 | public JsonNode toJsonNode () { |
| 347 | return this.json; |
| 348 | }; |
| 349 | |
| 350 | |
| 351 | /** |
| 352 | * Return the associated KoralQuery query object |
| 353 | * as a JSON string. This won't work, |
| 354 | * if the object was build using a {@link QueryBuilder}, |
| 355 | * therefore it is limited to mirror a deserialized KoralQuery |
| 356 | * object. |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 357 | * |
| Nils Diewald | 8904c1d | 2015-02-26 16:13:18 +0000 | [diff] [blame] | 358 | * @return A JSON string representing the query object |
| 359 | * of a deserialized KoralQuery object. |
| 360 | */ |
| 361 | public String toJsonString () { |
| 362 | if (this.json == null) |
| 363 | return "{}"; |
| 364 | return this.json.toString(); |
| 365 | }; |
| 366 | |
| 367 | |
| Nils Diewald | cec40f9 | 2015-02-19 22:20:02 +0000 | [diff] [blame] | 368 | // Deserialize koral:group |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 369 | private SpanQueryWrapper _groupFromJson (JsonNode json) |
| 370 | throws QueryException { |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 371 | |
| 372 | // No operation |
| 373 | if (!json.has("operation")) |
| 374 | throw new QueryException(703, "Group expects operation"); |
| 375 | |
| 376 | // Get operation |
| 377 | String operation = json.get("operation").asText(); |
| 378 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 379 | if (DEBUG) |
| 380 | log.trace("Found {} group", operation); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 381 | |
| 382 | if (!json.has("operands")) |
| 383 | throw new QueryException(704, "Operation needs operand list"); |
| 384 | |
| 385 | // Get all operands |
| 386 | JsonNode operands = json.get("operands"); |
| 387 | |
| 388 | if (operands == null || !operands.isArray()) |
| 389 | throw new QueryException(704, "Operation needs operand list"); |
| 390 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 391 | if (DEBUG) |
| 392 | log.trace("Operands are {}", operands); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 393 | |
| Akron | bb5d173 | 2015-06-22 01:22:40 +0200 | [diff] [blame] | 394 | SpanQueryWrapper spanReferenceQueryWrapper = _operationReferenceFromJSON( |
| 395 | json, operands); |
| margaretha | 144983d | 2015-05-07 11:52:17 +0200 | [diff] [blame] | 396 | if (spanReferenceQueryWrapper != null) { |
| 397 | return spanReferenceQueryWrapper; |
| 398 | } |
| 399 | |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 400 | // Branch on operation |
| 401 | switch (operation) { |
| Akron | 4055017 | 2015-08-04 03:06:12 +0200 | [diff] [blame] | 402 | case "operation:junction": |
| 403 | return this._operationJunctionFromJson(operands); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 404 | |
| Akron | 4055017 | 2015-08-04 03:06:12 +0200 | [diff] [blame] | 405 | case "operation:position": |
| 406 | return this._operationPositionFromJson(json, operands); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 407 | |
| Akron | 4055017 | 2015-08-04 03:06:12 +0200 | [diff] [blame] | 408 | case "operation:sequence": |
| 409 | return this._operationSequenceFromJson(json, operands); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 410 | |
| Akron | 4055017 | 2015-08-04 03:06:12 +0200 | [diff] [blame] | 411 | case "operation:class": |
| 412 | return this._operationClassFromJson(json, operands); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 413 | |
| Akron | 4055017 | 2015-08-04 03:06:12 +0200 | [diff] [blame] | 414 | case "operation:repetition": |
| 415 | return this._operationRepetitionFromJson(json, operands); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 416 | |
| Akron | 4055017 | 2015-08-04 03:06:12 +0200 | [diff] [blame] | 417 | case "operation:relation": |
| margaretha | 29521f9 | 2016-04-18 15:20:02 +0200 | [diff] [blame] | 418 | // if (!json.has("relType")) { |
| 419 | // throw new QueryException(717, |
| 420 | // "Missing relation node"); |
| 421 | // } |
| 422 | if (json.has("relType")) |
| 423 | return _operationRelationFromJson(operands, |
| 424 | json.get("relType")); |
| 425 | else if (json.has("relation")) { |
| 426 | return _operationRelationFromJson(operands, |
| 427 | json.get("relation")); |
| 428 | } |
| 429 | else { |
| Akron | 4055017 | 2015-08-04 03:06:12 +0200 | [diff] [blame] | 430 | throw new QueryException(717, "Missing relation node"); |
| 431 | } |
| Akron | 4055017 | 2015-08-04 03:06:12 +0200 | [diff] [blame] | 432 | /*throw new QueryException(765, |
| 433 | "Relations are currently not supported");*/ |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 434 | |
| Akron | 4055017 | 2015-08-04 03:06:12 +0200 | [diff] [blame] | 435 | case "operation:or": // Deprecated in favor of operation:junction |
| 436 | return this._operationJunctionFromJson(operands); |
| 437 | /* |
| 438 | case "operation:submatch": // Deprecated in favor of koral:reference |
| 439 | return this._operationSubmatchFromJson(json, operands); |
| 440 | */ |
| 441 | case "operation:disjunction": |
| 442 | return this._operationJunctionFromJson(operands); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 443 | }; |
| 444 | |
| 445 | // Unknown |
| 446 | throw new QueryException(711, "Unknown group operation"); |
| Nils Diewald | c925b49 | 2013-12-03 23:56:10 +0000 | [diff] [blame] | 447 | }; |
| 448 | |
| Akron | bb5d173 | 2015-06-22 01:22:40 +0200 | [diff] [blame] | 449 | |
| 450 | private SpanQueryWrapper _operationReferenceFromJSON (JsonNode node, |
| 451 | JsonNode operands) throws QueryException { |
| margaretha | 144983d | 2015-05-07 11:52:17 +0200 | [diff] [blame] | 452 | boolean isReference = false; |
| 453 | int classNum = -1; |
| 454 | int refOperandNum = -1; |
| 455 | JsonNode childNode; |
| 456 | |
| 457 | for (int i = 0; i < operands.size(); i++) { |
| 458 | childNode = operands.get(i); |
| 459 | if (childNode.has("@type") |
| 460 | && childNode.get("@type").asText() |
| 461 | .equals("koral:reference") |
| 462 | && childNode.has("operation") |
| 463 | && childNode.get("operation").asText() |
| 464 | .equals("operation:focus") |
| 465 | && !childNode.has("operands")) { |
| 466 | |
| 467 | if (childNode.has("classRef")) { |
| 468 | classNum = childNode.get("classRef").get(0).asInt(); |
| 469 | refOperandNum = i; |
| 470 | isReference = true; |
| 471 | break; |
| 472 | } |
| 473 | } |
| 474 | } |
| 475 | |
| 476 | if (isReference) { |
| 477 | JsonNode resolvedNode = _resolveReference(node, operands, |
| 478 | refOperandNum, classNum); |
| Akron | 626dd9f | 2016-06-08 10:08:55 +0200 | [diff] [blame^] | 479 | return new SpanReferenceQueryWrapper(this._fromKoral(resolvedNode), |
| margaretha | 144983d | 2015-05-07 11:52:17 +0200 | [diff] [blame] | 480 | (byte) classNum); |
| 481 | } |
| 482 | |
| 483 | return null; |
| 484 | } |
| 485 | |
| Akron | bb5d173 | 2015-06-22 01:22:40 +0200 | [diff] [blame] | 486 | |
| 487 | private JsonNode _resolveReference (JsonNode node, JsonNode operands, |
| margaretha | 144983d | 2015-05-07 11:52:17 +0200 | [diff] [blame] | 488 | int refOperandNum, int classNum) throws QueryException { |
| 489 | JsonNode referent = null; |
| 490 | ObjectMapper m = new ObjectMapper(); |
| 491 | ArrayNode newOperands = m.createArrayNode(); |
| 492 | boolean isReferentFound = false; |
| 493 | for (int i = 0; i < operands.size(); i++) { |
| 494 | if (i != refOperandNum) { |
| 495 | if (!isReferentFound) { |
| 496 | referent = _extractReferentClass(operands.get(i), classNum); |
| Akron | bb5d173 | 2015-06-22 01:22:40 +0200 | [diff] [blame] | 497 | if (referent != null) |
| 498 | isReferentFound = true; |
| margaretha | 144983d | 2015-05-07 11:52:17 +0200 | [diff] [blame] | 499 | } |
| 500 | newOperands.insert(i, operands.get(i)); |
| 501 | } |
| 502 | } |
| 503 | |
| 504 | if (isReferentFound) { |
| 505 | newOperands.insert(refOperandNum, referent); |
| 506 | ((ObjectNode) node).set("operands", newOperands); |
| 507 | return node; |
| 508 | } |
| 509 | else |
| 510 | throw new QueryException("Referent node is not found"); |
| 511 | |
| 512 | } |
| 513 | |
| Akron | bb5d173 | 2015-06-22 01:22:40 +0200 | [diff] [blame] | 514 | |
| 515 | private JsonNode _extractReferentClass (JsonNode node, int classNum) { |
| margaretha | 144983d | 2015-05-07 11:52:17 +0200 | [diff] [blame] | 516 | JsonNode referent; |
| 517 | if (node.has("classOut") && node.get("classOut").asInt() == classNum) { |
| margaretha | 144983d | 2015-05-07 11:52:17 +0200 | [diff] [blame] | 518 | return node; |
| 519 | } |
| 520 | else { |
| 521 | if (node.has("operands") && node.get("operands").isArray()) { |
| 522 | for (JsonNode childOperand : node.get("operands")) { |
| 523 | referent = _extractReferentClass(childOperand, classNum); |
| 524 | if (referent != null) { |
| 525 | return referent; |
| 526 | } |
| 527 | } |
| 528 | } |
| 529 | } |
| 530 | return null; |
| 531 | } |
| 532 | |
| margaretha | b097bac | 2015-04-15 11:37:02 +0200 | [diff] [blame] | 533 | |
| 534 | private SpanQueryWrapper _operationRelationFromJson (JsonNode operands, |
| 535 | JsonNode relation) throws QueryException { |
| margaretha | 5c26de4 | 2015-04-14 12:47:58 +0200 | [diff] [blame] | 536 | |
| 537 | if (operands.size() < 2) { |
| 538 | throw new QueryException(705, |
| 539 | "Number of operands is not acceptable"); |
| 540 | } |
| 541 | |
| Akron | 626dd9f | 2016-06-08 10:08:55 +0200 | [diff] [blame^] | 542 | SpanQueryWrapper operand1 = this._fromKoral(operands.get(0)); |
| 543 | SpanQueryWrapper operand2 = this._fromKoral(operands.get(1)); |
| Akron | bb5d173 | 2015-06-22 01:22:40 +0200 | [diff] [blame] | 544 | |
| margaretha | f70addb | 2015-04-27 13:17:18 +0200 | [diff] [blame] | 545 | String direction = ">:"; |
| 546 | if (operand1.isEmpty() && !operand2.isEmpty()) { |
| margaretha | 5c26de4 | 2015-04-14 12:47:58 +0200 | [diff] [blame] | 547 | direction = "<:"; |
| 548 | } |
| margaretha | 5c26de4 | 2015-04-14 12:47:58 +0200 | [diff] [blame] | 549 | |
| margaretha | f70addb | 2015-04-27 13:17:18 +0200 | [diff] [blame] | 550 | if (!relation.has("@type")) |
| 551 | throw new QueryException(701, |
| 552 | "JSON-LD group has no @type attribute"); |
| Akron | bb5d173 | 2015-06-22 01:22:40 +0200 | [diff] [blame] | 553 | |
| margaretha | f70addb | 2015-04-27 13:17:18 +0200 | [diff] [blame] | 554 | if (relation.get("@type").asText().equals("koral:relation")) { |
| 555 | if (!relation.has("wrap")) { |
| 556 | throw new QueryException(718, "Missing relation term"); |
| 557 | } |
| 558 | SpanQueryWrapper relationWrapper = _termFromJson( |
| Akron | bb5d173 | 2015-06-22 01:22:40 +0200 | [diff] [blame] | 559 | relation.get("wrap"), direction); |
| margaretha | f70addb | 2015-04-27 13:17:18 +0200 | [diff] [blame] | 560 | return new SpanRelationWrapper(relationWrapper, operand1, operand2); |
| 561 | } |
| 562 | else { |
| 563 | throw new QueryException(713, "Query type is not supported"); |
| 564 | } |
| margaretha | 5c26de4 | 2015-04-14 12:47:58 +0200 | [diff] [blame] | 565 | } |
| Nils Diewald | f399a67 | 2013-11-18 17:55:22 +0000 | [diff] [blame] | 566 | |
| margaretha | b097bac | 2015-04-15 11:37:02 +0200 | [diff] [blame] | 567 | |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 568 | // Deserialize operation:junction |
| 569 | private SpanQueryWrapper _operationJunctionFromJson (JsonNode operands) |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 570 | throws QueryException { |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 571 | SpanAlterQueryWrapper ssaq = new SpanAlterQueryWrapper(this.field); |
| 572 | for (JsonNode operand : operands) { |
| Akron | 626dd9f | 2016-06-08 10:08:55 +0200 | [diff] [blame^] | 573 | ssaq.or(this._fromKoral(operand)); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 574 | }; |
| 575 | return ssaq; |
| 576 | }; |
| Nils Diewald | c86aa48 | 2014-02-12 16:58:05 +0000 | [diff] [blame] | 577 | |
| Nils Diewald | 6409a92 | 2015-01-29 20:50:42 +0000 | [diff] [blame] | 578 | |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 579 | // Deserialize operation:position |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 580 | private SpanQueryWrapper _operationPositionFromJson (JsonNode json, |
| 581 | JsonNode operands) throws QueryException { |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 582 | if (operands.size() != 2) |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 583 | throw new QueryException(705, |
| 584 | "Number of operands is not acceptable"); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 585 | |
| Nils Diewald | 93d6d1b | 2015-02-02 21:47:43 +0000 | [diff] [blame] | 586 | String frame = "isAround"; |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 587 | // Temporary workaround for wrongly set overlaps |
| 588 | if (json.has("frames")) { |
| 589 | JsonNode frameN = json.get("frames"); |
| 590 | if (frameN.isArray()) { |
| 591 | frameN = json.get("frames").get(0); |
| 592 | if (frameN != null && frameN.isValueNode()) |
| 593 | frame = frameN.asText().substring(7); |
| 594 | }; |
| 595 | } |
| 596 | // <legacyCode> |
| 597 | else if (json.has("frame")) { |
| Nils Diewald | 93d6d1b | 2015-02-02 21:47:43 +0000 | [diff] [blame] | 598 | this.addMessage(0, "Frame is deprecated"); |
| 599 | |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 600 | JsonNode frameN = json.get("frame"); |
| 601 | if (frameN != null && frameN.isValueNode()) |
| 602 | frame = frameN.asText().substring(6); |
| 603 | }; |
| 604 | // </legacyCode> |
| 605 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 606 | if (DEBUG) |
| 607 | log.trace("Position frame is '{}'", frame); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 608 | |
| 609 | // Byte flag - should cover all 13 cases, i.e. two bytes long |
| 610 | byte flag = WITHIN; |
| 611 | switch (frame) { |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 612 | case "isAround": |
| 613 | break; |
| 614 | case "strictlyContains": |
| 615 | flag = REAL_WITHIN; |
| 616 | break; |
| 617 | case "isWithin": |
| 618 | break; |
| 619 | case "startsWith": |
| 620 | flag = STARTSWITH; |
| 621 | break; |
| 622 | case "endsWith": |
| 623 | flag = ENDSWITH; |
| 624 | break; |
| 625 | case "matches": |
| 626 | flag = MATCH; |
| 627 | break; |
| 628 | case "overlaps": |
| 629 | flag = OVERLAP; |
| 630 | this.addWarning(769, |
| 631 | "Overlap variant currently interpreted as overlap"); |
| 632 | break; |
| 633 | case "overlapsLeft": |
| 634 | // Temporary workaround |
| 635 | this.addWarning(769, |
| 636 | "Overlap variant currently interpreted as overlap"); |
| 637 | flag = OVERLAP; |
| 638 | break; |
| 639 | case "overlapsRight": |
| 640 | // Temporary workaround |
| 641 | this.addWarning(769, |
| 642 | "Overlap variant currently interpreted as overlap"); |
| 643 | flag = OVERLAP; |
| 644 | break; |
| 645 | case "strictlyOverlaps": |
| 646 | flag = REAL_OVERLAP; |
| 647 | break; |
| Nils Diewald | 93d6d1b | 2015-02-02 21:47:43 +0000 | [diff] [blame] | 648 | |
| 649 | // alignsLeft |
| 650 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 651 | default: |
| 652 | throw new QueryException(706, "Frame type is unknown"); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 653 | }; |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 654 | |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 655 | // The exclusion operator is no longer relevant |
| 656 | // <legacyCode> |
| 657 | Boolean exclude; |
| 658 | if (json.has("exclude") && json.get("exclude").asBoolean()) { |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 659 | throw new QueryException(760, |
| 660 | "Exclusion is currently not supported in position operations"); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 661 | }; |
| 662 | // </legacyCode> |
| 663 | |
| 664 | // Create SpanWithin Query |
| Akron | 626dd9f | 2016-06-08 10:08:55 +0200 | [diff] [blame^] | 665 | return new SpanWithinQueryWrapper(this._fromKoral(operands.get(0)), |
| 666 | this._fromKoral(operands.get(1)), flag); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 667 | }; |
| 668 | |
| Nils Diewald | 6409a92 | 2015-01-29 20:50:42 +0000 | [diff] [blame] | 669 | |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 670 | // Deserialize operation:repetition |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 671 | private SpanQueryWrapper _operationRepetitionFromJson (JsonNode json, |
| 672 | JsonNode operands) throws QueryException { |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 673 | |
| 674 | if (operands.size() != 1) |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 675 | throw new QueryException(705, |
| 676 | "Number of operands is not acceptable"); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 677 | |
| Nils Diewald | 6409a92 | 2015-01-29 20:50:42 +0000 | [diff] [blame] | 678 | int min = 0, max = 100; |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 679 | |
| 680 | if (json.has("boundary")) { |
| 681 | Boundary b = new Boundary(json.get("boundary"), 0, 100); |
| 682 | min = b.min; |
| 683 | max = b.max; |
| 684 | } |
| 685 | // <legacyCode> |
| 686 | else { |
| 687 | this.addMessage(0, "Setting boundary by min and max is deprecated"); |
| 688 | |
| 689 | // Set minimum value |
| 690 | if (json.has("min")) |
| 691 | min = json.get("min").asInt(0); |
| 692 | |
| 693 | // Set maximum value |
| 694 | if (json.has("max")) |
| 695 | max = json.get("max").asInt(100); |
| 696 | }; |
| 697 | // </legacyCode> |
| 698 | |
| 699 | // Sanitize max |
| 700 | if (max < 0) |
| 701 | max = 100; |
| 702 | else if (max > 100) |
| 703 | max = 100; |
| 704 | |
| 705 | // Sanitize min |
| 706 | if (min < 0) |
| 707 | min = 0; |
| 708 | else if (min > 100) |
| 709 | min = 100; |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 710 | |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 711 | // Check relation between min and max |
| 712 | if (min > max) |
| 713 | max = max; |
| 714 | |
| Akron | 626dd9f | 2016-06-08 10:08:55 +0200 | [diff] [blame^] | 715 | SpanQueryWrapper sqw = this._fromKoral(operands.get(0)); |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 716 | |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 717 | if (sqw.maybeExtension()) |
| 718 | return sqw.setMin(min).setMax(max); |
| 719 | |
| 720 | return new SpanRepetitionQueryWrapper(sqw, min, max); |
| 721 | }; |
| 722 | |
| 723 | |
| 724 | // Deserialize operation:submatch |
| 725 | @Deprecated |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 726 | private SpanQueryWrapper _operationSubmatchFromJson (JsonNode json, |
| 727 | JsonNode operands) throws QueryException { |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 728 | |
| 729 | int number = 1; |
| 730 | |
| 731 | this.addMessage(0, "operation:submatch is deprecated"); |
| 732 | |
| 733 | if (operands.size() != 1) |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 734 | throw new QueryException(705, |
| 735 | "Number of operands is not acceptable"); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 736 | |
| Nils Diewald | 6409a92 | 2015-01-29 20:50:42 +0000 | [diff] [blame] | 737 | // Use class reference |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 738 | if (json.has("classRef")) { |
| 739 | if (json.has("classRefOp")) { |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 740 | throw new QueryException(761, |
| 741 | "Class reference operators are currently not supported"); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 742 | }; |
| 743 | |
| 744 | number = json.get("classRef").get(0).asInt(); |
| 745 | } |
| Nils Diewald | 6409a92 | 2015-01-29 20:50:42 +0000 | [diff] [blame] | 746 | |
| 747 | // Use span reference |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 748 | else if (json.has("spanRef")) { |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 749 | throw new QueryException(762, |
| 750 | "Span references are currently not supported"); |
| 751 | }; |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 752 | |
| Akron | 626dd9f | 2016-06-08 10:08:55 +0200 | [diff] [blame^] | 753 | return new SpanFocusQueryWrapper(this._fromKoral(operands.get(0)), |
| Akron | bb5d173 | 2015-06-22 01:22:40 +0200 | [diff] [blame] | 754 | number); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 755 | }; |
| 756 | |
| 757 | |
| 758 | // Deserialize operation:class |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 759 | private SpanQueryWrapper _operationClassFromJson (JsonNode json, |
| 760 | JsonNode operands) throws QueryException { |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 761 | int number = 1; |
| 762 | |
| 763 | // Too many operands |
| 764 | if (operands.size() != 1) |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 765 | throw new QueryException(705, |
| 766 | "Number of operands is not acceptable"); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 767 | |
| 768 | // Get class number |
| 769 | if (json.has("classOut")) { |
| 770 | number = json.get("classOut").asInt(0); |
| 771 | } |
| 772 | // <legacyCode> |
| 773 | else if (json.has("class")) { |
| Nils Diewald | 93d6d1b | 2015-02-02 21:47:43 +0000 | [diff] [blame] | 774 | this.addMessage(0, "Class is deprecated"); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 775 | number = json.get("class").asInt(0); |
| 776 | }; |
| 777 | // </legacyCode> |
| 778 | |
| 779 | // Class reference check |
| 780 | if (json.has("classRefCheck")) { |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 781 | this.addWarning(764, "Class reference checks are currently " |
| 782 | + "not supported - results may not be correct"); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 783 | }; |
| 784 | |
| 785 | // Class reference operation |
| 786 | // This has to be done after class ref check |
| 787 | if (json.has("classRefOp")) { |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 788 | throw new QueryException(761, |
| 789 | "Class reference operators are currently not supported"); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 790 | }; |
| 791 | |
| 792 | // Number is set |
| 793 | if (number > 0) { |
| 794 | if (operands.size() != 1) { |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 795 | throw new QueryException(705, |
| 796 | "Number of operands is not acceptable"); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 797 | }; |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 798 | |
| 799 | if (DEBUG) |
| 800 | log.trace("Found Class definition for {}", number); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 801 | |
| 802 | if (number > MAX_CLASS_NUM) { |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 803 | throw new QueryException(709, "Valid class numbers exceeded"); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 804 | }; |
| 805 | |
| 806 | // Serialize operand |
| Akron | 626dd9f | 2016-06-08 10:08:55 +0200 | [diff] [blame^] | 807 | SpanQueryWrapper sqw = this._fromKoral(operands.get(0)); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 808 | |
| 809 | // Problematic |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 810 | if (sqw.maybeExtension()) |
| 811 | return sqw.setClassNumber(number); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 812 | |
| 813 | return new SpanClassQueryWrapper(sqw, number); |
| 814 | }; |
| 815 | |
| 816 | throw new QueryException(710, "Class attribute missing"); |
| 817 | }; |
| 818 | |
| 819 | |
| 820 | // Deserialize operation:sequence |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 821 | private SpanQueryWrapper _operationSequenceFromJson (JsonNode json, |
| 822 | JsonNode operands) throws QueryException { |
| Nils Diewald | 6409a92 | 2015-01-29 20:50:42 +0000 | [diff] [blame] | 823 | |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 824 | // Sequence with only one operand |
| 825 | if (operands.size() == 1) |
| Akron | 626dd9f | 2016-06-08 10:08:55 +0200 | [diff] [blame^] | 826 | return this._fromKoral(operands.get(0)); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 827 | |
| Nils Diewald | 8904c1d | 2015-02-26 16:13:18 +0000 | [diff] [blame] | 828 | SpanSequenceQueryWrapper sseqqw = this.builder().seq(); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 829 | |
| 830 | // Say if the operand order is important |
| 831 | if (json.has("inOrder")) |
| 832 | sseqqw.setInOrder(json.get("inOrder").asBoolean()); |
| 833 | |
| 834 | // Introduce distance constraints |
| 835 | // ATTENTION: Distances have to be set before segments are added |
| 836 | if (json.has("distances")) { |
| 837 | |
| 838 | // THIS IS NO LONGER NECESSARY, AS IT IS COVERED BY FRAMES |
| 839 | if (json.has("exclude") && json.get("exclude").asBoolean()) { |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 840 | throw new QueryException(763, |
| 841 | "Excluding distance constraints are currently not supported"); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 842 | }; |
| 843 | |
| 844 | if (!json.get("distances").isArray()) { |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 845 | throw new QueryException(707, |
| 846 | "Distance Constraints have to be defined as arrays"); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 847 | }; |
| 848 | |
| 849 | // TEMPORARY: Workaround for group distances |
| 850 | JsonNode firstDistance = json.get("distances").get(0); |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 851 | |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 852 | if (!firstDistance.has("@type")) { |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 853 | throw new QueryException(701, |
| 854 | "JSON-LD group has no @type attribute"); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 855 | }; |
| 856 | |
| 857 | JsonNode distances; |
| Nils Diewald | cec40f9 | 2015-02-19 22:20:02 +0000 | [diff] [blame] | 858 | if (firstDistance.get("@type").asText().equals("koral:group")) { |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 859 | if (!firstDistance.has("operands") |
| 860 | || !firstDistance.get("operands").isArray()) |
| 861 | throw new QueryException(704, |
| 862 | "Operation needs operand list"); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 863 | |
| 864 | distances = firstDistance.get("operands"); |
| 865 | } |
| 866 | |
| 867 | // Support korap distances |
| Akron | 784d13d | 2015-06-20 15:13:16 +0200 | [diff] [blame] | 868 | // TODO: Support cosmas distances |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 869 | else if (firstDistance.get("@type").asText() |
| 870 | .equals("koral:distance") |
| 871 | || firstDistance.get("@type").asText() |
| 872 | .equals("cosmas:distance")) { |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 873 | distances = json.get("distances"); |
| 874 | } |
| 875 | |
| 876 | else |
| 877 | throw new QueryException(708, "No valid distances defined"); |
| 878 | |
| 879 | // Add all distance constraint to query |
| 880 | for (JsonNode constraint : distances) { |
| 881 | String unit = "w"; |
| 882 | if (constraint.has("key")) |
| 883 | unit = constraint.get("key").asText(); |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 884 | |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 885 | // There is a maximum of 100 fix |
| 886 | int min = 0, max = 100; |
| 887 | if (constraint.has("boundary")) { |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 888 | Boundary b = new Boundary(constraint.get("boundary"), 0, |
| 889 | 100); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 890 | min = b.min; |
| 891 | max = b.max; |
| 892 | } |
| Akron | 784d13d | 2015-06-20 15:13:16 +0200 | [diff] [blame] | 893 | |
| 894 | // <legacy> |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 895 | else { |
| 896 | if (constraint.has("min")) |
| 897 | min = constraint.get("min").asInt(0); |
| 898 | if (constraint.has("max")) |
| 899 | max = constraint.get("max").asInt(100); |
| 900 | }; |
| Akron | 784d13d | 2015-06-20 15:13:16 +0200 | [diff] [blame] | 901 | // </legacy> |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 902 | |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 903 | // Add foundry and layer to the unit for new indices |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 904 | if (constraint.has("foundry") && constraint.has("layer") |
| 905 | && constraint.get("foundry").asText().length() > 0 |
| 906 | && constraint.get("layer").asText().length() > 0) { |
| 907 | |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 908 | StringBuilder value = new StringBuilder(); |
| 909 | value.append(constraint.get("foundry").asText()); |
| 910 | value.append('/'); |
| 911 | value.append(constraint.get("layer").asText()); |
| 912 | value.append(':').append(unit); |
| 913 | unit = value.toString(); |
| Akron | d292690 | 2016-02-13 18:37:36 +0100 | [diff] [blame] | 914 | } |
| 915 | |
| 916 | // Use default foundry and layer - currently only base is supported! |
| Akron | c12567c | 2016-06-03 00:40:52 +0200 | [diff] [blame] | 917 | else if (unit.equals("s") || unit.equals("p") |
| 918 | || unit.equals("t")) { |
| Akron | d292690 | 2016-02-13 18:37:36 +0100 | [diff] [blame] | 919 | StringBuilder value = new StringBuilder(); |
| 920 | unit = value.append("base/s:").append(unit).toString(); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 921 | }; |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 922 | |
| Akron | 4e2bc0e | 2016-02-17 12:23:46 +0100 | [diff] [blame] | 923 | // Workaround for koral:distance vs cosmas:distance |
| 924 | if (constraint.get("@type").asText().equals("koral:distance")) { |
| 925 | min++; |
| 926 | max++; |
| 927 | }; |
| 928 | |
| Akron | 4d5fe19 | 2016-02-16 00:22:14 +0100 | [diff] [blame] | 929 | // Set distance exclusion |
| 930 | Boolean exclusion = false; |
| 931 | if (constraint.has("exclude")) |
| 932 | exclusion = constraint.get("exclude").asBoolean(); |
| 933 | |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 934 | // Sanitize boundary |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 935 | if (max < min) |
| 936 | max = min; |
| 937 | |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 938 | if (DEBUG) |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 939 | log.trace("Add distance constraint of '{}': {}-{}", unit, |
| 940 | min, max); |
| 941 | |
| Akron | 4d5fe19 | 2016-02-16 00:22:14 +0100 | [diff] [blame] | 942 | sseqqw.withConstraint(min, max, unit, exclusion); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 943 | }; |
| 944 | }; |
| 945 | |
| 946 | // Add segments to sequence |
| 947 | for (JsonNode operand : operands) { |
| Akron | 626dd9f | 2016-06-08 10:08:55 +0200 | [diff] [blame^] | 948 | sseqqw.append(this._fromKoral(operand)); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 949 | }; |
| 950 | |
| 951 | // inOrder was set to false without a distance constraint |
| 952 | if (!sseqqw.isInOrder() && !sseqqw.hasConstraints()) { |
| Akron | 784d13d | 2015-06-20 15:13:16 +0200 | [diff] [blame] | 953 | if (DEBUG) |
| 954 | log.trace("Add distance constraint - for the normal inorder case"); |
| 955 | |
| Nils Diewald | 6409a92 | 2015-01-29 20:50:42 +0000 | [diff] [blame] | 956 | sseqqw.withConstraint(1, 1, "w"); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 957 | }; |
| 958 | |
| 959 | return sseqqw; |
| 960 | }; |
| 961 | |
| 962 | |
| Nils Diewald | cec40f9 | 2015-02-19 22:20:02 +0000 | [diff] [blame] | 963 | // Deserialize koral:token |
| Eliza Margaretha | b1a5ed4 | 2015-01-26 10:37:12 +0000 | [diff] [blame] | 964 | private SpanQueryWrapper _segFromJson (JsonNode json) throws QueryException { |
| Akron | c63697c | 2015-06-17 22:32:02 +0200 | [diff] [blame] | 965 | |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 966 | if (!json.has("@type")) |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 967 | throw new QueryException(701, |
| 968 | "JSON-LD group has no @type attribute"); |
| Nils Diewald | 33fcb5d | 2014-11-07 23:27:03 +0000 | [diff] [blame] | 969 | |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 970 | String type = json.get("@type").asText(); |
| Nils Diewald | 33fcb5d | 2014-11-07 23:27:03 +0000 | [diff] [blame] | 971 | |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 972 | if (DEBUG) |
| 973 | log.trace("Wrap new token definition by {}", type); |
| Nils Diewald | 1455e1e | 2014-08-01 16:12:43 +0000 | [diff] [blame] | 974 | |
| Nils Diewald | 6409a92 | 2015-01-29 20:50:42 +0000 | [diff] [blame] | 975 | // Branch on type |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 976 | switch (type) { |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 977 | case "koral:term": |
| 978 | // String match = "match:eq"; |
| 979 | // if (json.has("match")) |
| 980 | // match = json.get("match").asText(); |
| 981 | // |
| 982 | // switch (match) { |
| 983 | // |
| 984 | // case "match:ne": |
| 985 | // if (DEBUG) |
| 986 | // log.trace("Term is negated"); |
| 987 | // |
| 988 | // SpanSegmentQueryWrapper ssqw = |
| 989 | // (SpanSegmentQueryWrapper) this._termFromJson(json); |
| 990 | // |
| 991 | // ssqw.makeNegative(); |
| 992 | // |
| 993 | // return this.seg().without(ssqw); |
| 994 | // |
| 995 | // case "match:eq": |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 996 | return this._termFromJson(json); |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 997 | // }; |
| 998 | // |
| 999 | // throw new QueryException(741, "Match relation unknown"); |
| Nils Diewald | 26087ea | 2013-12-05 16:51:30 +0000 | [diff] [blame] | 1000 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1001 | case "koral:termGroup": |
| Nils Diewald | 26087ea | 2013-12-05 16:51:30 +0000 | [diff] [blame] | 1002 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1003 | if (!json.has("operands")) |
| 1004 | throw new QueryException(742, |
| 1005 | "Term group needs operand list"); |
| Nils Diewald | 26087ea | 2013-12-05 16:51:30 +0000 | [diff] [blame] | 1006 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1007 | // Get operands |
| 1008 | JsonNode operands = json.get("operands"); |
| Nils Diewald | c86aa48 | 2014-02-12 16:58:05 +0000 | [diff] [blame] | 1009 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1010 | SpanSegmentQueryWrapper ssegqw = this.builder().seg(); |
| Nils Diewald | c86aa48 | 2014-02-12 16:58:05 +0000 | [diff] [blame] | 1011 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1012 | if (!json.has("relation")) |
| 1013 | throw new QueryException(743, |
| 1014 | "Term group expects a relation"); |
| Nils Diewald | 1220e3e | 2014-11-08 03:18:58 +0000 | [diff] [blame] | 1015 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1016 | switch (json.get("relation").asText()) { |
| 1017 | case "relation:and": |
| Eliza Margaretha | b1a5ed4 | 2015-01-26 10:37:12 +0000 | [diff] [blame] | 1018 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1019 | for (JsonNode operand : operands) { |
| 1020 | SpanQueryWrapper part = this._segFromJson(operand); |
| 1021 | if (part instanceof SpanAlterQueryWrapper) { |
| 1022 | ssegqw.with((SpanAlterQueryWrapper) part); |
| 1023 | } |
| 1024 | else if (part instanceof SpanRegexQueryWrapper) { |
| 1025 | ssegqw.with((SpanRegexQueryWrapper) part); |
| 1026 | } |
| 1027 | else if (part instanceof SpanSegmentQueryWrapper) { |
| 1028 | ssegqw.with((SpanSegmentQueryWrapper) part); |
| 1029 | } |
| 1030 | else { |
| 1031 | throw new QueryException(744, |
| 1032 | "Operand not supported in term group"); |
| 1033 | }; |
| 1034 | } |
| 1035 | ; |
| 1036 | return ssegqw; |
| Eliza Margaretha | b1a5ed4 | 2015-01-26 10:37:12 +0000 | [diff] [blame] | 1037 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1038 | case "relation:or": |
| 1039 | |
| 1040 | SpanAlterQueryWrapper ssaq = new SpanAlterQueryWrapper( |
| 1041 | this.field); |
| 1042 | for (JsonNode operand : operands) { |
| 1043 | ssaq.or(this._segFromJson(operand)); |
| 1044 | } |
| 1045 | ; |
| 1046 | return ssaq; |
| 1047 | } |
| 1048 | ; |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 1049 | }; |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1050 | throw new QueryException(745, "Token type is not supported"); |
| Nils Diewald | 4d183ea | 2013-12-05 02:51:38 +0000 | [diff] [blame] | 1051 | }; |
| Nils Diewald | 4d183ea | 2013-12-05 02:51:38 +0000 | [diff] [blame] | 1052 | |
| margaretha | b097bac | 2015-04-15 11:37:02 +0200 | [diff] [blame] | 1053 | |
| margaretha | 5c26de4 | 2015-04-14 12:47:58 +0200 | [diff] [blame] | 1054 | private SpanQueryWrapper _termFromJson (JsonNode json) |
| 1055 | throws QueryException { |
| 1056 | return _termFromJson(json, null); |
| 1057 | } |
| Nils Diewald | 4d183ea | 2013-12-05 02:51:38 +0000 | [diff] [blame] | 1058 | |
| margaretha | b097bac | 2015-04-15 11:37:02 +0200 | [diff] [blame] | 1059 | |
| Nils Diewald | cec40f9 | 2015-02-19 22:20:02 +0000 | [diff] [blame] | 1060 | // Deserialize koral:term |
| Akron | 907d3d7 | 2015-06-30 11:32:42 +0200 | [diff] [blame] | 1061 | // TODO: Not optimal as it does not respect non-term |
| margaretha | b097bac | 2015-04-15 11:37:02 +0200 | [diff] [blame] | 1062 | private SpanQueryWrapper _termFromJson (JsonNode json, String direction) |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1063 | throws QueryException { |
| Akron | d2ddac9 | 2016-02-13 16:56:21 +0100 | [diff] [blame] | 1064 | |
| Nils Diewald | 6409a92 | 2015-01-29 20:50:42 +0000 | [diff] [blame] | 1065 | if (!json.has("key") || json.get("key").asText().length() < 1) { |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1066 | if (!json.has("attr")) |
| 1067 | throw new QueryException(740, |
| 1068 | "Key definition is missing in term or span"); |
| Nils Diewald | 6409a92 | 2015-01-29 20:50:42 +0000 | [diff] [blame] | 1069 | }; |
| Nils Diewald | 33fcb5d | 2014-11-07 23:27:03 +0000 | [diff] [blame] | 1070 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1071 | if (!json.has("@type")) { |
| 1072 | throw new QueryException(701, |
| 1073 | "JSON-LD group has no @type attribute"); |
| 1074 | }; |
| 1075 | |
| 1076 | Boolean isTerm = json.get("@type").asText().equals("koral:term") ? true |
| 1077 | : false; |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 1078 | Boolean isCaseInsensitive = false; |
| Nils Diewald | c86aa48 | 2014-02-12 16:58:05 +0000 | [diff] [blame] | 1079 | |
| Akron | 907d3d7 | 2015-06-30 11:32:42 +0200 | [diff] [blame] | 1080 | |
| 1081 | // Ugly direction hack |
| 1082 | if (direction != null && direction.equals("<>:")) { |
| 1083 | isTerm = false; |
| 1084 | direction = null; |
| 1085 | }; |
| 1086 | |
| Akron | d504f21 | 2015-06-20 00:27:54 +0200 | [diff] [blame] | 1087 | // <legacy> |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1088 | if (json.has("caseInsensitive") |
| Akron | bb5d173 | 2015-06-22 01:22:40 +0200 | [diff] [blame] | 1089 | && json.get("caseInsensitive").asBoolean()) { |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 1090 | isCaseInsensitive = true; |
| Akron | 738ed00 | 2015-06-18 12:07:50 +0200 | [diff] [blame] | 1091 | } |
| Akron | d504f21 | 2015-06-20 00:27:54 +0200 | [diff] [blame] | 1092 | // </legacy> |
| Akron | 738ed00 | 2015-06-18 12:07:50 +0200 | [diff] [blame] | 1093 | |
| 1094 | // Flags |
| 1095 | else if (json.has("flags") && json.get("flags").isArray()) { |
| 1096 | Iterator<JsonNode> flags = json.get("flags").elements(); |
| 1097 | while (flags.hasNext()) { |
| Akron | d504f21 | 2015-06-20 00:27:54 +0200 | [diff] [blame] | 1098 | String flag = flags.next().asText(); |
| 1099 | if (flag.equals("flags:caseInsensitive")) { |
| Akron | 738ed00 | 2015-06-18 12:07:50 +0200 | [diff] [blame] | 1100 | isCaseInsensitive = true; |
| Akron | d504f21 | 2015-06-20 00:27:54 +0200 | [diff] [blame] | 1101 | } |
| 1102 | else { |
| 1103 | this.addWarning(748, "Flag is unknown", flag); |
| Akron | 738ed00 | 2015-06-18 12:07:50 +0200 | [diff] [blame] | 1104 | }; |
| 1105 | }; |
| 1106 | }; |
| Nils Diewald | c86aa48 | 2014-02-12 16:58:05 +0000 | [diff] [blame] | 1107 | |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 1108 | StringBuilder value = new StringBuilder(); |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1109 | |
| Akron | a883aa5 | 2015-06-18 22:07:31 +0200 | [diff] [blame] | 1110 | if (direction != null) |
| margaretha | 5c26de4 | 2015-04-14 12:47:58 +0200 | [diff] [blame] | 1111 | value.append(direction); |
| margaretha | 5c26de4 | 2015-04-14 12:47:58 +0200 | [diff] [blame] | 1112 | |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 1113 | // expect orth? expect lemma? |
| 1114 | // s:den | i:den | cnx/l:die | mate/m:mood:ind | cnx/syn:@PREMOD | |
| 1115 | // mate/m:number:sg | opennlp/p:ART |
| Nils Diewald | c86aa48 | 2014-02-12 16:58:05 +0000 | [diff] [blame] | 1116 | |
| Akron | a883aa5 | 2015-06-18 22:07:31 +0200 | [diff] [blame] | 1117 | if (json.has("foundry") && json.get("foundry").asText().length() > 0) { |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 1118 | value.append(json.get("foundry").asText()).append('/'); |
| Akron | a883aa5 | 2015-06-18 22:07:31 +0200 | [diff] [blame] | 1119 | }; |
| Nils Diewald | c86aa48 | 2014-02-12 16:58:05 +0000 | [diff] [blame] | 1120 | |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 1121 | // No default foundry defined |
| 1122 | if (json.has("layer") && json.get("layer").asText().length() > 0) { |
| 1123 | String layer = json.get("layer").asText(); |
| 1124 | switch (layer) { |
| Nils Diewald | c86aa48 | 2014-02-12 16:58:05 +0000 | [diff] [blame] | 1125 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1126 | case "lemma": |
| 1127 | layer = "l"; |
| 1128 | break; |
| Nils Diewald | c86aa48 | 2014-02-12 16:58:05 +0000 | [diff] [blame] | 1129 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1130 | case "pos": |
| 1131 | layer = "p"; |
| 1132 | break; |
| Nils Diewald | 164f8be | 2014-02-13 02:43:16 +0000 | [diff] [blame] | 1133 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1134 | case "orth": |
| Akron | d2ddac9 | 2016-02-13 16:56:21 +0100 | [diff] [blame] | 1135 | // TODO: THIS IS AN UGLY HACK! AND SHOULD BE NAMED "SURFACE" or . OR * |
| 1136 | layer = "."; |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1137 | break; |
| Nils Diewald | 164f8be | 2014-02-13 02:43:16 +0000 | [diff] [blame] | 1138 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1139 | case "struct": |
| 1140 | layer = "s"; |
| 1141 | break; |
| Nils Diewald | 164f8be | 2014-02-13 02:43:16 +0000 | [diff] [blame] | 1142 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1143 | case "const": |
| 1144 | layer = "c"; |
| 1145 | break; |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 1146 | }; |
| Nils Diewald | c471b18 | 2014-11-19 22:51:15 +0000 | [diff] [blame] | 1147 | |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 1148 | if (isCaseInsensitive && isTerm) { |
| Akron | d2ddac9 | 2016-02-13 16:56:21 +0100 | [diff] [blame] | 1149 | if (layer.equals(".")) |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 1150 | layer = "i"; |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 1151 | else { |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1152 | this.addWarning(767, |
| 1153 | "Case insensitivity is currently not supported for this layer"); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 1154 | }; |
| 1155 | }; |
| Nils Diewald | ea7239a | 2014-11-14 14:01:56 +0000 | [diff] [blame] | 1156 | |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 1157 | // Ignore foundry for orth layer |
| Akron | d2ddac9 | 2016-02-13 16:56:21 +0100 | [diff] [blame] | 1158 | if (layer.equals(".")) { |
| Akron | 13db615 | 2016-02-19 14:08:38 +0100 | [diff] [blame] | 1159 | layer = "s"; |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 1160 | value.setLength(0); |
| Akron | d2ddac9 | 2016-02-13 16:56:21 +0100 | [diff] [blame] | 1161 | } |
| 1162 | else if (layer.equals("i")) { |
| 1163 | value.setLength(0); |
| 1164 | }; |
| Nils Diewald | c86aa48 | 2014-02-12 16:58:05 +0000 | [diff] [blame] | 1165 | |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 1166 | value.append(layer).append(':'); |
| 1167 | }; |
| Nils Diewald | c86aa48 | 2014-02-12 16:58:05 +0000 | [diff] [blame] | 1168 | |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 1169 | if (json.has("key") && json.get("key").asText().length() > 0) { |
| 1170 | String key = json.get("key").asText(); |
| 1171 | value.append(isCaseInsensitive ? key.toLowerCase() : key); |
| 1172 | }; |
| Nils Diewald | 3430aa2 | 2014-11-07 13:39:03 +0000 | [diff] [blame] | 1173 | |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 1174 | if (json.has("value") && json.get("value").asText().length() > 0) |
| 1175 | value.append(':').append(json.get("value").asText()); |
| Nils Diewald | c86aa48 | 2014-02-12 16:58:05 +0000 | [diff] [blame] | 1176 | |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 1177 | // Regular expression or wildcard |
| 1178 | if (isTerm && json.has("type")) { |
| Nils Diewald | 6409a92 | 2015-01-29 20:50:42 +0000 | [diff] [blame] | 1179 | |
| Nils Diewald | 8904c1d | 2015-02-26 16:13:18 +0000 | [diff] [blame] | 1180 | QueryBuilder qb = this.builder(); |
| 1181 | |
| Nils Diewald | 6409a92 | 2015-01-29 20:50:42 +0000 | [diff] [blame] | 1182 | // Branch on type |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 1183 | switch (json.get("type").asText()) { |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1184 | case "type:regex": |
| 1185 | return qb.seg(qb.re(value.toString(), isCaseInsensitive)); |
| Nils Diewald | 6409a92 | 2015-01-29 20:50:42 +0000 | [diff] [blame] | 1186 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1187 | case "type:wildcard": |
| 1188 | return qb.seq(qb.wc(value.toString(), isCaseInsensitive)); |
| Nils Diewald | 6409a92 | 2015-01-29 20:50:42 +0000 | [diff] [blame] | 1189 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1190 | case "type:string": |
| 1191 | break; |
| Nils Diewald | 6409a92 | 2015-01-29 20:50:42 +0000 | [diff] [blame] | 1192 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1193 | default: |
| 1194 | this.addWarning(746, |
| 1195 | "Term type is not supported - treated as a string"); |
| Nils Diewald | d75e6f6 | 2015-01-28 23:44:56 +0000 | [diff] [blame] | 1196 | }; |
| 1197 | }; |
| Nils Diewald | c86aa48 | 2014-02-12 16:58:05 +0000 | [diff] [blame] | 1198 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1199 | if (isTerm) { |
| Eliza Margaretha | 641b20a | 2015-02-16 17:23:13 +0000 | [diff] [blame] | 1200 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1201 | String match = "match:eq"; |
| 1202 | if (json.has("match")) { |
| 1203 | match = json.get("match").asText(); |
| 1204 | } |
| Eliza Margaretha | 641b20a | 2015-02-16 17:23:13 +0000 | [diff] [blame] | 1205 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1206 | SpanSegmentQueryWrapper ssqw = this.builder().seg(value.toString()); |
| 1207 | if (match.equals("match:ne")) { |
| 1208 | if (DEBUG) |
| 1209 | log.trace("Term is negated"); |
| 1210 | ssqw.makeNegative(); |
| 1211 | return this.builder().seg().without(ssqw); |
| 1212 | } |
| 1213 | else if (match.equals("match:eq")) { |
| 1214 | return ssqw; |
| 1215 | } |
| 1216 | else { |
| 1217 | throw new QueryException(741, "Match relation unknown"); |
| 1218 | } |
| Eliza Margaretha | 641b20a | 2015-02-16 17:23:13 +0000 | [diff] [blame] | 1219 | } |
| Nils Diewald | c471b18 | 2014-11-19 22:51:15 +0000 | [diff] [blame] | 1220 | |
| Eliza Margaretha | 221349f | 2015-01-29 17:27:41 +0000 | [diff] [blame] | 1221 | if (json.has("attr")) { |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1222 | JsonNode attrNode = json.get("attr"); |
| 1223 | if (!attrNode.has("@type")) { |
| 1224 | throw new QueryException(701, |
| 1225 | "JSON-LD group has no @type attribute"); |
| 1226 | } |
| Eliza Margaretha | 221349f | 2015-01-29 17:27:41 +0000 | [diff] [blame] | 1227 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1228 | if (value.toString().isEmpty()) { |
| 1229 | return _createElementAttrFromJson(null, json, attrNode); |
| 1230 | // this.addWarning(771, |
| 1231 | // "Arbitraty elements with attributes are currently not supported."); |
| 1232 | } |
| 1233 | else { |
| 1234 | SpanQueryWrapper elementWithIdWrapper = this.builder().tag( |
| 1235 | value.toString()); |
| 1236 | if (elementWithIdWrapper == null) { |
| 1237 | return null; |
| 1238 | } |
| 1239 | return _createElementAttrFromJson(elementWithIdWrapper, json, |
| 1240 | attrNode); |
| 1241 | } |
| Nils Diewald | 6409a92 | 2015-01-29 20:50:42 +0000 | [diff] [blame] | 1242 | }; |
| Nils Diewald | 8904c1d | 2015-02-26 16:13:18 +0000 | [diff] [blame] | 1243 | return this.builder().tag(value.toString()); |
| Nils Diewald | c86aa48 | 2014-02-12 16:58:05 +0000 | [diff] [blame] | 1244 | }; |
| 1245 | |
| Nils Diewald | 8904c1d | 2015-02-26 16:13:18 +0000 | [diff] [blame] | 1246 | |
| 1247 | // Deserialize elements with attributes |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1248 | private SpanQueryWrapper _createElementAttrFromJson ( |
| 1249 | SpanQueryWrapper elementWithIdWrapper, JsonNode json, |
| 1250 | JsonNode attrNode) throws QueryException { |
| Eliza Margaretha | 1969c2b | 2015-02-23 15:13:03 +0000 | [diff] [blame] | 1251 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1252 | if (attrNode.get("@type").asText().equals("koral:term")) { |
| 1253 | SpanQueryWrapper attrWrapper = _attrFromJson(json.get("attr")); |
| 1254 | if (attrWrapper != null) { |
| 1255 | if (elementWithIdWrapper != null) { |
| 1256 | return new SpanWithAttributeQueryWrapper( |
| 1257 | elementWithIdWrapper, attrWrapper); |
| 1258 | } |
| 1259 | else { |
| 1260 | return new SpanWithAttributeQueryWrapper(attrWrapper); |
| 1261 | } |
| 1262 | } |
| 1263 | else { |
| 1264 | throw new QueryException(747, "Attribute is null"); |
| 1265 | } |
| 1266 | } |
| Nils Diewald | 8904c1d | 2015-02-26 16:13:18 +0000 | [diff] [blame] | 1267 | else if (attrNode.get("@type").asText().equals("koral:termGroup")) { |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1268 | return _handleAttrGroup(elementWithIdWrapper, attrNode); |
| 1269 | } |
| 1270 | else { |
| 1271 | this.addWarning(715, "Attribute type is not supported"); |
| 1272 | } |
| 1273 | return elementWithIdWrapper; |
| 1274 | } |
| Nils Diewald | 8904c1d | 2015-02-26 16:13:18 +0000 | [diff] [blame] | 1275 | |
| 1276 | |
| 1277 | // Deserialize attribute groups |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1278 | private SpanQueryWrapper _handleAttrGroup ( |
| 1279 | SpanQueryWrapper elementWithIdWrapper, JsonNode attrNode) |
| 1280 | throws QueryException { |
| 1281 | if (!attrNode.has("relation")) { |
| 1282 | throw new QueryException(743, "Term group expects a relation"); |
| 1283 | } |
| 1284 | if (!attrNode.has("operands")) { |
| 1285 | throw new QueryException(742, "Term group needs operand list"); |
| 1286 | } |
| Eliza Margaretha | 1969c2b | 2015-02-23 15:13:03 +0000 | [diff] [blame] | 1287 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1288 | String relation = attrNode.get("relation").asText(); |
| 1289 | JsonNode operands = attrNode.get("operands"); |
| Eliza Margaretha | 1969c2b | 2015-02-23 15:13:03 +0000 | [diff] [blame] | 1290 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1291 | SpanQueryWrapper attrWrapper; |
| 1292 | if ("relation:and".equals(relation)) { |
| 1293 | List<SpanQueryWrapper> wrapperList = new ArrayList<SpanQueryWrapper>(); |
| 1294 | for (JsonNode operand : operands) { |
| 1295 | attrWrapper = _termFromJson(operand); |
| 1296 | if (attrWrapper == null) { |
| 1297 | throw new QueryException(747, "Attribute is null"); |
| 1298 | } |
| 1299 | wrapperList.add(attrWrapper); |
| 1300 | } |
| Eliza Margaretha | 1969c2b | 2015-02-23 15:13:03 +0000 | [diff] [blame] | 1301 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1302 | if (elementWithIdWrapper != null) { |
| 1303 | return new SpanWithAttributeQueryWrapper(elementWithIdWrapper, |
| 1304 | wrapperList); |
| 1305 | } |
| 1306 | else { |
| 1307 | return new SpanWithAttributeQueryWrapper(wrapperList); |
| 1308 | } |
| 1309 | } |
| 1310 | else if ("relation:or".equals(relation)) { |
| 1311 | SpanAlterQueryWrapper saq = new SpanAlterQueryWrapper(field); |
| 1312 | SpanWithAttributeQueryWrapper saqw; |
| 1313 | for (JsonNode operand : operands) { |
| 1314 | attrWrapper = _termFromJson(operand); |
| 1315 | if (attrWrapper == null) { |
| 1316 | throw new QueryException(747, "Attribute is null"); |
| 1317 | } |
| 1318 | if (elementWithIdWrapper != null) { |
| 1319 | saqw = new SpanWithAttributeQueryWrapper( |
| 1320 | elementWithIdWrapper, attrWrapper); |
| 1321 | } |
| 1322 | else { |
| 1323 | saqw = new SpanWithAttributeQueryWrapper(attrWrapper); |
| 1324 | } |
| 1325 | saq.or(saqw); |
| 1326 | } |
| 1327 | return saq; |
| 1328 | } |
| 1329 | else { |
| 1330 | throw new QueryException(716, "Unknown relation"); |
| 1331 | } |
| 1332 | } |
| 1333 | |
| Nils Diewald | 6409a92 | 2015-01-29 20:50:42 +0000 | [diff] [blame] | 1334 | |
| Nils Diewald | 83c9b16 | 2015-02-03 21:05:07 +0000 | [diff] [blame] | 1335 | // Get attributes from a json termgroup |
| Nils Diewald | 6409a92 | 2015-01-29 20:50:42 +0000 | [diff] [blame] | 1336 | private SpanQueryWrapper _attrFromJson (JsonNode attrNode) |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1337 | throws QueryException { |
| Eliza Margaretha | 221349f | 2015-01-29 17:27:41 +0000 | [diff] [blame] | 1338 | |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1339 | if (attrNode.has("key")) { |
| 1340 | return _termFromJson(attrNode); |
| 1341 | } |
| 1342 | else if (attrNode.has("tokenarity") || attrNode.has("arity")) { |
| 1343 | this.addWarning(770, "Arity attributes are currently not supported" |
| 1344 | + " - results may not be correct"); |
| 1345 | } |
| 1346 | else if (attrNode.has("root")) { |
| 1347 | String rootValue = attrNode.get("root").asText(); |
| 1348 | if (rootValue.equals("true") || rootValue.equals("false")) { |
| Akron | c63697c | 2015-06-17 22:32:02 +0200 | [diff] [blame] | 1349 | |
| 1350 | // TODO: Here do not refer to 'tokens'!!! |
| margaretha | 29521f9 | 2016-04-18 15:20:02 +0200 | [diff] [blame] | 1351 | // EM: what should it be? property? |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1352 | return new SpanAttributeQueryWrapper( |
| 1353 | new SpanSimpleQueryWrapper("tokens", "@root", |
| 1354 | Boolean.valueOf(rootValue))); |
| Eliza Margaretha | 221349f | 2015-01-29 17:27:41 +0000 | [diff] [blame] | 1355 | } |
| 1356 | } |
| Nils Diewald | bb33da2 | 2015-03-04 16:24:25 +0000 | [diff] [blame] | 1357 | return null; |
| Nils Diewald | bbd39a5 | 2015-02-23 19:56:57 +0000 | [diff] [blame] | 1358 | }; |
| Nils Diewald | f399a67 | 2013-11-18 17:55:22 +0000 | [diff] [blame] | 1359 | }; |