From 2edd9764942ec2d62cabcb4190a69921c60af293 Mon Sep 17 00:00:00 2001 From: Adam Dickmeiss Date: Thu, 12 Sep 2013 14:22:28 +0200 Subject: [PATCH] facetSort, facetStart honored. For both Solr and SRU 2.0 --- include/yaz/facet.h | 5 +- src/facet.asn | 3 +- src/facet.c | 47 +++++--------- src/solr.c | 54 ++++++++++++---- src/sru-p.h | 4 +- src/sru_facet.c | 170 +++++++++++++++++++++++++++++++++++++++++++-------- src/srw.c | 23 +++++-- src/srwutil.c | 16 ++++- ztest/ztest.c | 6 +- 9 files changed, 245 insertions(+), 83 deletions(-) diff --git a/include/yaz/facet.h b/include/yaz/facet.h index 43e1eea..4455980 100644 --- a/include/yaz/facet.h +++ b/include/yaz/facet.h @@ -57,8 +57,9 @@ struct yaz_facet_attr { /* or number converted to a string */ /* defaults to 'any' */ char useattrbuff[30]; /* for converting numbers to strings */ - char *relation; /* @attr 2, defaults to '=' */ - int limit; /* for facet attributes */ + int sortorder; + int limit; + int start; }; YAZ_EXPORT diff --git a/src/facet.asn b/src/facet.asn index f22eedf..7950bd1 100644 --- a/src/facet.asn +++ b/src/facet.asn @@ -7,8 +7,9 @@ FacetList ::= SEQUENCE OF FacetField; FacetField ::= SEQUENCE { -- attributes will specify: -- 1=use (field name) - -- 2=sortorder 0=most frequent, 1=least frequent, .. + -- 2=sortorder 0=count descending, 1=alpha ascending .. -- 3=limit (integer) + -- 4=start (integer) attributes [1] IMPLICIT AttributeList, terms [2] IMPLICIT SEQUENCE OF FacetTerm OPTIONAL } diff --git a/src/facet.c b/src/facet.c index 40b5e1c..b65091a 100644 --- a/src/facet.c +++ b/src/facet.c @@ -69,10 +69,11 @@ void yaz_facet_attr_init(struct yaz_facet_attr *attr_values) { attr_values->errcode = 0; attr_values->errstring = 0; - attr_values->relation = 0; + attr_values->sortorder = 0; attr_values->useattr = 0; attr_values->useattrbuff[0] = 0; attr_values->limit = 0; + attr_values->start = 0; } static const char *stringattr(Z_ComplexAttribute *c) @@ -119,41 +120,17 @@ static void useattr(Z_AttributeElement *ae, struct yaz_facet_attr *av) } -static void sortorderattr(Z_AttributeElement *ae, struct yaz_facet_attr *av) +static void numattr(Z_AttributeElement *ae, struct yaz_facet_attr *av, + int *v) { if (ae->which == Z_AttributeValue_numeric) { - if (*ae->value.numeric == 0) - av->relation = "desc"; - else if (*ae->value.numeric == 1) - av->relation = "asc"; - else if (*ae->value.numeric == 3) - av->relation = "unknown/unordered"; - else - { - av->errcode = YAZ_BIB1_UNSUPP_RELATION_ATTRIBUTE; - sprintf(av->useattrbuff, ODR_INT_PRINTF, - *ae-> attributeType); - av->errstring = av->useattrbuff; - } - } - else - { - av->errcode = YAZ_BIB1_UNSUPP_RELATION_ATTRIBUTE; - av->errstring = "non-numeric relation attribute"; - } -} - -static void limitattr(Z_AttributeElement *ae, struct yaz_facet_attr *av) -{ - if (ae->which == Z_AttributeValue_numeric) - { - av->limit = *ae->value.numeric; + *v = *ae->value.numeric; } else { av->errcode = YAZ_BIB1_UNSUPP_ATTRIBUTE; - av->errstring = "non-numeric limit attribute"; + av->errstring = "non-numeric limit/sort/start attribute"; } } @@ -181,12 +158,16 @@ void yaz_facet_attr_get_z_attributes(const Z_AttributeList *attributes, useattr(ae, av); } else if (*ae->attributeType == 2) - { /* sortorder */ - sortorderattr(ae, av); + { + numattr(ae, av, &av->sortorder); } else if (*ae->attributeType == 3) - { /* limit */ - limitattr(ae, av); + { + numattr(ae, av, &av->limit); + } + else if (*ae->attributeType == 4) + { + numattr(ae, av, &av->start); } else { /* unknown attribute */ diff --git a/src/solr.c b/src/solr.c index ca35e56..9897bb1 100644 --- a/src/solr.c +++ b/src/solr.c @@ -397,32 +397,62 @@ static int yaz_solr_encode_facet_field( struct yaz_facet_attr attr_values; yaz_facet_attr_init(&attr_values); yaz_facet_attr_get_z_attributes(attribute_list, &attr_values); - // TODO do we want to support server decided if (attr_values.errcode) return -1; if (attr_values.useattr) { WRBUF wrbuf = wrbuf_alloc(); - wrbuf_puts(wrbuf, (char *) attr_values.useattr); yaz_add_name_value_str(encode, name, value, i, "facet.field", - odr_strdup(encode, wrbuf_cstr(wrbuf))); + odr_strdup(encode, attr_values.useattr)); + if (attr_values.limit > 0) { - WRBUF wrbuf2 = wrbuf_alloc(); - Odr_int olimit; - wrbuf_puts(wrbuf2, "f."); - wrbuf_puts(wrbuf2, wrbuf_cstr(wrbuf)); - wrbuf_puts(wrbuf2, ".facet.limit"); - olimit = attr_values.limit; + Odr_int v = attr_values.limit; + wrbuf_rewind(wrbuf); + wrbuf_printf(wrbuf, "f.%s.facet.limit", attr_values.useattr); + yaz_add_name_value_int(encode, name, value, i, + odr_strdup(encode, wrbuf_cstr(wrbuf)), + &v); + } + if (attr_values.start > 1) + { + Odr_int v = attr_values.start - 1; + wrbuf_rewind(wrbuf); + wrbuf_printf(wrbuf, "f.%s.facet.offset", attr_values.useattr); yaz_add_name_value_int(encode, name, value, i, - odr_strdup(encode, wrbuf_cstr(wrbuf2)), - &olimit); - wrbuf_destroy(wrbuf2); + odr_strdup(encode, wrbuf_cstr(wrbuf)), + &v); + } + if (attr_values.sortorder == 1) + { + wrbuf_rewind(wrbuf); + wrbuf_printf(wrbuf, "f.%s.facet.sort", attr_values.useattr); + yaz_add_name_value_str(encode, name, value, i, + odr_strdup(encode, wrbuf_cstr(wrbuf)), + "index"); } wrbuf_destroy(wrbuf); } + else + { + if (attr_values.limit > 0) + { + Odr_int v = attr_values.limit; + yaz_add_name_value_int(encode, name, value, i, "facet.limit", &v); + } + if (attr_values.start > 1) + { + Odr_int v = attr_values.start - 1; + yaz_add_name_value_int(encode, name, value, i, "facet.offset", &v); + } + if (attr_values.sortorder == 1) + { + yaz_add_name_value_str(encode, name, value, i, "facet.sort", + "index"); + } + } return 0; } diff --git a/src/sru-p.h b/src/sru-p.h index fb6b290..ea7b3e4 100644 --- a/src/sru-p.h +++ b/src/sru-p.h @@ -39,7 +39,9 @@ Z_AttributeList *yaz_use_attribute_create(ODR o, const char *name); char *yaz_negotiate_sru_version(char *input_ver); -void yaz_sru_facet_request(ODR, Z_FacetList **facetList, const char **limit); +void yaz_sru_facet_request(ODR, Z_FacetList **facetList, + const char **limit, const char **start, + const char **sort); #if YAZ_HAVE_XML2 #include diff --git a/src/sru_facet.c b/src/sru_facet.c index 29c5a68..87eb9ed 100644 --- a/src/sru_facet.c +++ b/src/sru_facet.c @@ -24,15 +24,51 @@ #include #include -void yaz_sru_facet_request(ODR o, Z_FacetList **facetList, const char **limit) +static void insert_field(WRBUF w, const char *field, size_t length, + const char *attr) +{ + const char *cp0 = wrbuf_cstr(w); + const char *cp = cp0; + + while (1) + { + const char *cp2 = strstr(cp, "@attr 1="); + if (!cp2) + break; + cp = cp2 + 8; + if (!strncmp(cp, field, length) && + (cp[length] == ' ' || cp[length] == ',' || cp[length] == '\0')) + { + /* found the field */ + + cp += length; + wrbuf_insert(w, cp - cp0, attr, strlen(attr)); + wrbuf_insert(w, cp - cp0, " ", 1); + return; + } + while (*cp && *cp != ',') + cp++; + } + if (wrbuf_len(w)) + wrbuf_puts(w, ","); + wrbuf_puts(w, "@attr 1="); + wrbuf_write(w, field, length); + wrbuf_puts(w, " "); + wrbuf_puts(w, attr); +} + +void yaz_sru_facet_request(ODR o, Z_FacetList **facetList, const char **limit, + const char **start, const char **sort) { if (o->direction == ODR_ENCODE) { Z_FacetList *fl = *facetList; if (fl) { + WRBUF w_limit = wrbuf_alloc(); + WRBUF w_start = wrbuf_alloc(); + WRBUF w_sort = wrbuf_alloc(); int i; - WRBUF w = wrbuf_alloc(); for (i = 0; i < fl->num; i++) { struct yaz_facet_attr av; @@ -41,51 +77,131 @@ void yaz_sru_facet_request(ODR o, Z_FacetList **facetList, const char **limit) &av); if (av.errcode == 0) { - wrbuf_printf(w, "%d", av.limit ? av.limit : -1); - if (av.useattr) - wrbuf_printf(w, ":%s,", av.useattr); - /* av.relation not considered yet */ + if (av.limit) + { + wrbuf_printf(w_limit, "%d", av.limit); + if (av.useattr) + wrbuf_printf(w_limit, ":%s", av.useattr); + wrbuf_puts(w_limit, ","); + } + if (av.start || av.useattr) + { + wrbuf_printf(w_start, "%d", av.start); + if (av.useattr) + wrbuf_printf(w_start, ":%s", av.useattr); + wrbuf_puts(w_start, ","); + } + if (av.sortorder == 1) + { + /* allow sorting per field */ + /* not really according to spec */ + wrbuf_printf(w_sort, "alphanumeric"); + if (av.useattr) + wrbuf_printf(w_sort, ":%s", av.useattr); + wrbuf_puts(w_sort, ","); + } } } - if (wrbuf_len(w) > 0) + if (wrbuf_len(w_limit) > 1) + { + wrbuf_cut_right(w_limit, 1); /* remove , */ + *limit = odr_strdup(o, wrbuf_cstr(w_limit)); + } + if (wrbuf_len(w_start) > 1) { - wrbuf_cut_right(w, 1); /* remove , */ - *limit = odr_strdup(o, wrbuf_cstr(w)); + wrbuf_cut_right(w_start, 1); /* remove , */ + *start = odr_strdup(o, wrbuf_cstr(w_start)); } - wrbuf_destroy(w); + if (wrbuf_len(w_sort) > 1) + { + wrbuf_cut_right(w_sort, 1); /* remove , */ + *sort = odr_strdup(o, wrbuf_cstr(w_sort)); + } + wrbuf_destroy(w_limit); + wrbuf_destroy(w_start); + wrbuf_destroy(w_sort); } } else if (o->direction == ODR_DECODE) { - const char *cp = *limit; - *facetList = 0; - if (cp) + WRBUF w = wrbuf_alloc(); + + if (*limit) + { + const char *cp = *limit; + int nor = 0; + int val = 0; + while (sscanf(cp, "%d%n", &val, &nor) >= 1 && nor > 0) + { + cp += nor; + if (*cp == ':') /* field name follows */ + { + char tmp[40]; + const char *cp0 = ++cp; + while (*cp && *cp != ',') + cp++; + sprintf(tmp, "@attr 3=%d", val); + insert_field(w, cp0, cp - cp0, tmp); + } + if (*cp != ',') + break; + cp++; + } + } + if (*start) { + const char *cp = *start; int nor = 0; - int limit_val = 0; - WRBUF w = wrbuf_alloc(); - while (sscanf(cp, "%d%n", &limit_val, &nor) >= 1 && nor > 0) + int val = 0; + while (sscanf(cp, "%d%n", &val, &nor) >= 1 && nor > 0) { cp += nor; - if (wrbuf_len(w)) - wrbuf_puts(w, ","); if (*cp == ':') /* field name follows */ { - wrbuf_puts(w, "@attr 1="); - while (*++cp && *cp != ',') - wrbuf_putc(w, *cp); - wrbuf_puts(w, " "); + char tmp[40]; + const char *cp0 = ++cp; + while (*cp && *cp != ',') + cp++; + sprintf(tmp, "@attr 4=%d", val); + insert_field(w, cp0, cp - cp0, tmp); + } + if (*cp != ',') + break; + cp++; + } + } + + if (*sort) + { + const char *cp = *sort; + while (1) + { + int val = 0; + const char *cp0 = cp; + while (*cp && *cp != ':' && *cp != ',') + cp++; + if (!strncmp(cp0, "alphanumeric", cp - cp0)) + val = 1; + if (*cp == ':') /* field name follows */ + { + char tmp[40]; + cp0 = ++cp; + while (*cp && *cp != ',') + cp++; + sprintf(tmp, "@attr 2=%d", val); + insert_field(w, cp0, cp - cp0, tmp); } - if (limit_val != -1) - wrbuf_printf(w, "@attr 3=%d", limit_val); if (*cp != ',') break; cp++; } - if (wrbuf_len(w)) - *facetList = yaz_pqf_parse_facet_list(o, wrbuf_cstr(w)); - wrbuf_destroy(w); } + + if (wrbuf_len(w)) + *facetList = yaz_pqf_parse_facet_list(o, wrbuf_cstr(w)); + else + *facetList = 0; + wrbuf_destroy(w); } } diff --git a/src/srw.c b/src/srw.c index ca46a44..17b7c39 100644 --- a/src/srw.c +++ b/src/srw.c @@ -568,6 +568,8 @@ int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data, char *recordPacking = 0; char *recordXMLEscaping = 0; const char *facetLimit = 0; + const char *facetStart = 0; + const char *facetSort = 0; (*p)->which = Z_SRW_searchRetrieve_request; req = (*p)->u.request = (Z_SRW_searchRetrieveRequest *) @@ -630,10 +632,17 @@ int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data, else if (yaz_match_xsd_string(ptr, "stylesheet", o, &req->stylesheet)) ; - else if (yaz_match_xsd_string(ptr, "database", o, &req->database)) + else if (yaz_match_xsd_string(ptr, "database", o, + &req->database)) ; else if (yaz_match_xsd_string(ptr, "facetLimit", o, - (char**) &facetLimit)) + (char**) &facetLimit)) + ; + else if (yaz_match_xsd_string(ptr, "facetStart", o, + (char**) &facetStart)) + ; + else if (yaz_match_xsd_string(ptr, "facetSort", o, + (char**) &facetSort)) ; } if (!req->query) @@ -650,7 +659,8 @@ int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data, { req->recordPacking = recordPacking; } - yaz_sru_facet_request(o, &req->facetList, &facetLimit); + yaz_sru_facet_request(o, &req->facetList, &facetLimit, &facetStart, + &facetSort); } else if (!xmlStrcmp(method->name, BAD_CAST "searchRetrieveResponse")) { @@ -925,8 +935,13 @@ int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data, add_xsd_string(ptr, "database", req->database); { const char *limit = 0; - yaz_sru_facet_request(o, &req->facetList, &limit); + const char *start = 0; + const char *sort = 0; + yaz_sru_facet_request(o, &req->facetList, &limit, &start, + &sort); add_xsd_string(ptr, "facetLimit", limit); + add_xsd_string(ptr, "facetStart", start); + add_xsd_string(ptr, "facetSort", sort); } } else if ((*p)->which == Z_SRW_searchRetrieve_response) diff --git a/src/srwutil.c b/src/srwutil.c index 1937a77..2591fc9 100644 --- a/src/srwutil.c +++ b/src/srwutil.c @@ -398,6 +398,8 @@ int yaz_sru_decode(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu, char *maximumTerms = 0; char *responsePosition = 0; const char *facetLimit = 0; + const char *facetStart = 0; + const char *facetSort = 0; Z_SRW_extra_arg *extra_args = 0; #endif char **uri_name; @@ -471,6 +473,10 @@ int yaz_sru_decode(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu, responsePosition = v; else if (!strcmp(n, "facetLimit")) facetLimit = v; + else if (!strcmp(n, "facetStart")) + facetStart = v; + else if (!strcmp(n, "facetSort")) + facetSort = v; else if (!strcmp(n, "extraRequestData")) ; /* ignoring extraRequestData */ else if (n[0] == 'x' && n[1] == '-') @@ -556,7 +562,7 @@ int yaz_sru_decode(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu, sr->u.request->packing = recordPacking; sr->u.request->stylesheet = stylesheet; yaz_sru_facet_request(decode , &sr->u.request->facetList, - &facetLimit); + &facetLimit, &facetStart, &facetSort); yaz_sru_decode_integer(decode, "maximumRecords", maximumRecords, &sr->u.request->maximumRecords, @@ -961,10 +967,16 @@ static int yaz_get_sru_parms(const Z_SRW_PDU *srw_pdu, ODR encode, srw_pdu->u.request->resultSetTTL); { const char *facetLimit = 0; + const char *facetStart = 0; + const char *facetSort = 0; yaz_sru_facet_request(encode, &srw_pdu->u.request->facetList, - &facetLimit); + &facetLimit, &facetStart, &facetSort); yaz_add_name_value_str(encode, name, value, &i, "facetLimit", (char *) facetLimit); + yaz_add_name_value_str(encode, name, value, &i, "facetStart", + (char *) facetStart); + yaz_add_name_value_str(encode, name, value, &i, "facetSort", + (char *) facetSort); } break; case Z_SRW_explain_request: diff --git a/ztest/ztest.c b/ztest/ztest.c index aa91186..32b8857 100644 --- a/ztest/ztest.c +++ b/ztest/ztest.c @@ -277,7 +277,11 @@ Z_OtherInformation *build_facet_response(ODR odr, Z_FacetList *facet_list) { attrvalues.limit = 10; yaz_facet_attr_get_z_attributes(facet_list->elements[index]->attributes, &attrvalues); - yaz_log(YLOG_LOG, "Attributes: %s %d ", attrvalues.useattr, attrvalues.limit); + yaz_log(YLOG_LOG, "Attributes: %s limit=%d start=%d sort=%d", + attrvalues.useattr, + attrvalues.limit, + attrvalues.start, + attrvalues.sortorder); if (attrvalues.errstring) yaz_log(YLOG_LOG, "Error parsing attributes: %s", attrvalues.errstring); if (attrvalues.limit > 0 && attrvalues.useattr) { -- 1.7.10.4