1 /* This file is part of the YAZ toolkit.
2 * Copyright (C) 1995-2013 Index Data
3 * See the file LICENSE for details.
7 * \brief Implements RPN to SOLR conversion
16 #include <yaz/rpn2solr.h>
17 #include <yaz/xmalloc.h>
18 #include <yaz/diagbib1.h>
19 #include <yaz/z-core.h>
20 #include <yaz/wrbuf.h>
22 static void wrbuf_vputs(const char *buf, void *client_data)
24 wrbuf_write((WRBUF) client_data, buf, strlen(buf));
27 static const char *lookup_index_from_string_attr(Z_AttributeList *attributes)
30 int server_choice = 1;
31 for (j = 0; j < attributes->num_attributes; j++)
33 Z_AttributeElement *ae = attributes->attributes[j];
34 if (*ae->attributeType == 1) /* use attribute */
36 if (ae->which == Z_AttributeValue_complex)
38 Z_ComplexAttribute *ca = ae->value.complex;
40 for (i = 0; i < ca->num_list; i++)
42 Z_StringOrNumeric *son = ca->list[i];
43 if (son->which == Z_StringOrNumeric_string)
47 server_choice = 0; /* not serverChoice because we have use attr */
51 return "cql.serverChoice";
55 static const char *lookup_relation_index_from_attr(Z_AttributeList *attributes)
58 for (j = 0; j < attributes->num_attributes; j++)
60 Z_AttributeElement *ae = attributes->attributes[j];
61 if (*ae->attributeType == 2) /* relation attribute */
63 if (ae->which == Z_AttributeValue_numeric)
65 /* Only support for numeric relation */
66 Odr_int *relation = ae->value.numeric;
67 /* map this numeric to representation in SOLR */
70 /* Unsure on whether this is the relation attribute constants? */
71 case Z_ProximityOperator_Prox_lessThan:
73 case Z_ProximityOperator_Prox_lessThanOrEqual:
75 case Z_ProximityOperator_Prox_equal:
77 case Z_ProximityOperator_Prox_greaterThanOrEqual:
79 case Z_ProximityOperator_Prox_greaterThan:
81 case Z_ProximityOperator_Prox_notEqual:
84 /* phonetic is not implemented */
87 /* stem is not not implemented */
90 /* relevance is supported in SOLR, but not implemented yet */
93 /* Invalid relation */
98 /* Can we have a complex relation value?
99 Should we implement something?
109 const char *relation;
116 static int rpn2solr_attr(solr_transform_t ct,
117 Z_AttributeList *attributes, WRBUF w, struct solr_attr *solr_attr)
119 const char *relation = solr_lookup_reverse(ct, "relation.", attributes);
120 const char *index = solr_lookup_reverse(ct, "index.", attributes);
121 const char *structure = solr_lookup_reverse(ct, "structure.", attributes);
122 /* Assume this is not a range */
123 solr_attr->is_range = 0;
125 /* if transform (properties) do not match, we'll just use a USE string attribute (bug #2978) */
127 index = lookup_index_from_string_attr(attributes);
129 /* Attempt to fix bug #2978: Look for a relation attribute */
131 relation = lookup_relation_index_from_attr(attributes);
135 solr_transform_set_error(ct, YAZ_BIB1_UNSUPP_USE_ATTRIBUTE, 0);
138 /* for serverChoice we omit index+relation+structure */
139 if (strcmp(index, "cql.serverChoice"))
141 solr_attr->index = index;
144 if (!strcmp(relation, "exact")) {
145 /* TODO Exact match does not exists in SOLR. Need to use specific field type */
148 else if (!strcmp(relation, "eq")) {
151 else if (!strcmp(relation, "<")) {
152 solr_attr->is_range = 1;
153 solr_attr->begin = "[* TO ";
154 solr_attr->close = "}";
156 else if (!strcmp(relation, "le")) {
157 solr_attr->is_range = 2;
158 solr_attr->begin = "[* TO ";
159 solr_attr->close = "]";
161 else if (!strcmp(relation, "ge")) {
162 solr_attr->is_range = 4;
163 solr_attr->begin = "[";
164 solr_attr->close = " TO *]";
166 else if (!strcmp(relation, ">")) {
167 solr_attr->is_range = 5;
168 solr_attr->begin = "{";
169 solr_attr->close = " TO *]";
171 solr_attr->relation = relation;
173 // TODO is this valid for Solr?
177 if (strcmp(structure, "*"))
180 wrbuf_puts(w, structure);
182 solr_attr->index = 0;
188 solr_attr->index = 0;
192 static Odr_int get_truncation(Z_AttributesPlusTerm *apt)
195 Z_AttributeList *attributes = apt->attributes;
196 for (j = 0; j < attributes->num_attributes; j++)
198 Z_AttributeElement *ae = attributes->attributes[j];
199 if (*ae->attributeType == 5) /* truncation attribute */
201 if (ae->which == Z_AttributeValue_numeric)
203 return *(ae->value.numeric);
205 else if (ae->which == Z_AttributeValue_complex) {
207 //yaz_log(YLOG_DEBUG, "Z_Attribute_complex");
208 /* Complex: Shouldn't happen */
212 /* No truncation given */
216 #define SOLR_SPECIAL "+-&|!(){}[]^\"~*?:\\"
218 static int rpn2solr_simple(solr_transform_t ct,
219 Z_Operand *q, WRBUF w, struct solr_attr *solr_attr)
222 if (q->which != Z_Operand_APT)
225 solr_transform_set_error(ct, YAZ_BIB1_RESULT_SET_UNSUPP_AS_A_SEARCH_TERM, 0);
229 Z_AttributesPlusTerm *apt = q->u.attributesPlusTerm;
230 Z_Term *term = apt->term;
231 const char *sterm = 0;
233 Odr_int trunc = get_truncation(apt);
236 ret = rpn2solr_attr(ct, apt->attributes, w, solr_attr);
238 if (trunc == 0 || trunc == 1 || trunc == 100 || trunc == 104)
242 solr_transform_set_error(ct, YAZ_BIB1_UNSUPP_TRUNCATION_ATTRIBUTE, 0);
248 lterm = term->u.general->len;
249 sterm = (const char *) term->u.general->buf;
252 wrbuf_printf(w, ODR_INT_PRINTF, *term->u.numeric);
254 case Z_Term_characterString:
255 sterm = term->u.characterString;
256 lterm = strlen(sterm);
260 solr_transform_set_error(ct, YAZ_BIB1_TERM_TYPE_UNSUPP, 0);
268 for (i = 0 ; i < lterm; i++)
273 for (i = 0 ; i < lterm; i++)
275 if (sterm[i] == '\\' && i < lterm - 1)
278 if (strchr(SOLR_SPECIAL, sterm[i]))
280 wrbuf_putc(w, sterm[i]);
282 else if (sterm[i] == '?' && trunc == 104)
286 else if (sterm[i] == '#' && trunc == 104)
290 else if (strchr(SOLR_SPECIAL, sterm[i]))
293 wrbuf_putc(w, sterm[i]);
296 wrbuf_putc(w, sterm[i]);
304 solr_attr->term = wrbuf_cstr(w);
311 static int solr_write_range(void (*pr)(const char *buf, void *client_data),
313 struct solr_attr *solr_attr_left,
314 struct solr_attr *solr_attr_right)
316 pr(solr_attr_left->index, client_data);
317 pr(":", client_data);
318 pr(solr_attr_left->begin, client_data);
319 pr(solr_attr_left->term, client_data);
320 pr(" TO ", client_data);
321 pr(solr_attr_right->term, client_data);
322 pr(solr_attr_right->close, client_data);
326 static int solr_write_structure(void (*pr)(const char *buf, void *client_data),
328 struct solr_attr *solr_attr)
330 if (solr_attr->index) {
331 pr(solr_attr->index, client_data);
332 pr(":", client_data);
334 if (solr_attr->is_range) {
335 pr(solr_attr->begin, client_data);
336 pr(solr_attr->term, client_data);
337 pr(solr_attr->close, client_data);
339 else if (solr_attr->term)
340 pr(solr_attr->term, client_data);
346 static int solr_write_and_or_range(void (*pr)(const char *buf, void *client_data),
348 struct solr_attr *solr_attr_left,
349 struct solr_attr *solr_attr_right)
351 if (solr_attr_left->is_range &&
352 solr_attr_right->is_range &&
353 !strcmp(solr_attr_left->index, solr_attr_right->index))
355 if (solr_attr_left->is_range > 3 && solr_attr_right->is_range < 3)
356 return solr_write_range(pr, client_data, solr_attr_left, solr_attr_right);
357 else if (solr_attr_left->is_range < 3 && solr_attr_right->is_range > 3)
358 return solr_write_range(pr, client_data, solr_attr_right, solr_attr_left);
360 solr_write_structure(pr, client_data, solr_attr_left);
361 pr(" AND ", client_data);
362 solr_write_structure(pr, client_data, solr_attr_right);
366 static void solr_attr_init(struct solr_attr *solr_attr) {
367 solr_attr->index = 0;
368 solr_attr->relation = 0;
369 solr_attr->is_range = 0;
374 static int rpn2solr_structure(solr_transform_t ct,
375 void (*pr)(const char *buf, void *client_data),
377 Z_RPNStructure *q, int nested,
378 WRBUF wa, struct solr_attr *solr_attr)
380 if (q->which == Z_RPNStructure_simple) {
381 solr_attr_init(solr_attr);
382 return rpn2solr_simple(ct, q->u.simple, wa, solr_attr);
386 Z_Operator *op = q->u.complex->roperator;
388 struct solr_attr solr_attr_left, solr_attr_right;
389 WRBUF w_left = wrbuf_alloc();
390 WRBUF w_right = wrbuf_alloc();
393 pr("(", client_data);
395 solr_attr_init(&solr_attr_left);
396 r = rpn2solr_structure(ct, pr, client_data, q->u.complex->s1, 1, w_left, &solr_attr_left);
400 wrbuf_destroy(w_left);
403 solr_attr_init(&solr_attr_right);
405 r = rpn2solr_structure(ct, pr, client_data, q->u.complex->s2, 1, w_right, &solr_attr_right);
407 wrbuf_destroy(w_left);
408 wrbuf_destroy(w_right);
415 solr_write_and_or_range(pr, client_data, &solr_attr_left, &solr_attr_right);
418 solr_write_structure(pr, client_data, &solr_attr_left);
419 pr(" OR ", client_data);
420 solr_write_structure(pr, client_data, &solr_attr_right);
422 case Z_Operator_and_not:
423 solr_write_structure(pr, client_data, &solr_attr_left);
424 pr(" AND NOT ", client_data);
425 solr_write_structure(pr, client_data, &solr_attr_right);
427 case Z_Operator_prox:
428 solr_transform_set_error(ct, YAZ_BIB1_UNSUPP_SEARCH, 0);
429 wrbuf_destroy(w_left);
430 wrbuf_destroy(w_right);
435 pr(")", client_data);
437 solr_attr_init(solr_attr);
438 wrbuf_destroy(w_left);
439 wrbuf_destroy(w_right);
444 int solr_transform_rpn2solr_stream(solr_transform_t ct,
445 void (*pr)(const char *buf, void *client_data),
450 WRBUF w = wrbuf_alloc();
451 struct solr_attr solr_attr;
452 solr_transform_set_error(ct, 0, 0);
453 solr_attr_init(&solr_attr);
454 r = rpn2solr_structure(ct, pr, client_data, q->RPNStructure, 0, w, &solr_attr);
455 solr_write_structure(pr, client_data, &solr_attr);
461 int solr_transform_rpn2solr_wrbuf(solr_transform_t ct,
465 return solr_transform_rpn2solr_stream(ct, wrbuf_vputs, w, q);
471 * c-file-style: "Stroustrup"
472 * indent-tabs-mode: nil
474 * vim: shiftwidth=4 tabstop=8 expandtab