facetSort, facetStart honored.
authorAdam Dickmeiss <adam@indexdata.dk>
Thu, 12 Sep 2013 12:22:28 +0000 (14:22 +0200)
committerAdam Dickmeiss <adam@indexdata.dk>
Thu, 12 Sep 2013 12:22:28 +0000 (14:22 +0200)
For both Solr and SRU 2.0

include/yaz/facet.h
src/facet.asn
src/facet.c
src/solr.c
src/sru-p.h
src/sru_facet.c
src/srw.c
src/srwutil.c
ztest/ztest.c

index 43e1eea..4455980 100644 (file)
@@ -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
index f22eedf..7950bd1 100644 (file)
@@ -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
 }
index 40b5e1c..b65091a 100644 (file)
@@ -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 */
index ca35e56..9897bb1 100644 (file)
@@ -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;
 }
 
index fb6b290..ea7b3e4 100644 (file)
@@ -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 <libxml/parser.h>
index 29c5a68..87eb9ed 100644 (file)
 #include <yaz/pquery.h>
 #include <yaz/facet.h>
 
-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);
     }
 }
 
index ca46a44..17b7c39 100644 (file)
--- 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)
index 1937a77..2591fc9 100644 (file)
@@ -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:
index aa91186..32b8857 100644 (file)
@@ -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) {