+ double diff = atof(this_entry.buf[j]) -
+ atof(sort_info->entries[i]->buf[j]);
+ rel = 0;
+ if (diff > 0.0)
+ rel = 1;
+ else if (diff < 0.0)
+ rel = -1;
+ }
+ else
+ {
+ rel = memcmp (this_entry.buf[j], sort_info->entries[i]->buf[j],
+ SORT_IDX_ENTRYSIZE);
+ }
+ if (rel)
+ break;
+ }
+ if (!rel)
+ break;
+ if (criteria[j].relation == 'A')
+ {
+ if (rel > 0)
+ break;
+ }
+ else if (criteria[j].relation == 'D')
+ {
+ if (rel < 0)
+ break;
+ }
+ }
+ ++i;
+ j = sort_info->max_entries;
+ if (i == j)
+ return;
+
+ if (sort_info->num_entries == j)
+ --j;
+ else
+ j = (sort_info->num_entries)++;
+ new_entry = sort_info->entries[j];
+ while (j != i)
+ {
+ sort_info->entries[j] = sort_info->entries[j-1];
+ --j;
+ }
+ sort_info->entries[i] = new_entry;
+ assert (new_entry);
+ for (i = 0; i<num_criteria; i++)
+ memcpy (new_entry->buf[i], this_entry.buf[i], SORT_IDX_ENTRYSIZE);
+ new_entry->sysno = sysno;
+ new_entry->score = -1;
+}
+
+void resultSetInsertRank (ZebraHandle zh, struct zset_sort_info *sort_info,
+ zint sysno, int score, int relation)
+{
+ struct zset_sort_entry *new_entry = NULL;
+ int i, j;
+
+ i = sort_info->num_entries;
+ while (--i >= 0)
+ {
+ int rel = 0;
+
+ rel = score - sort_info->entries[i]->score;
+
+ if (relation == 'D')
+ {
+ if (rel >= 0)
+ break;
+ }
+ else if (relation == 'A')
+ {
+ if (rel <= 0)
+ break;
+ }
+ }
+ ++i;
+ j = sort_info->max_entries;
+ if (i == j)
+ return;
+
+ if (sort_info->num_entries == j)
+ --j;
+ else
+ j = (sort_info->num_entries)++;
+
+ new_entry = sort_info->entries[j];
+ while (j != i)
+ {
+ sort_info->entries[j] = sort_info->entries[j-1];
+ --j;
+ }
+ sort_info->entries[i] = new_entry;
+ assert (new_entry);
+ new_entry->sysno = sysno;
+ new_entry->score = score;
+}
+
+void resultSetSort (ZebraHandle zh, NMEM nmem,
+ int num_input_setnames, const char **input_setnames,
+ const char *output_setname,
+ Z_SortKeySpecList *sort_sequence, int *sort_status)
+{
+ ZebraSet sset;
+ RSET rset;
+
+ if (num_input_setnames == 0)
+ {
+ zh->errCode = 208;
+ return ;
+ }
+ if (num_input_setnames > 1)
+ {
+ zh->errCode = 230;
+ return;
+ }
+ yaz_log (LOG_DEBUG, "result set sort input=%s output=%s",
+ *input_setnames, output_setname);
+ sset = resultSetGet (zh, input_setnames[0]);
+ if (!sset)
+ {
+ zh->errCode = 30;
+ zh->errString = nmem_strdup (nmem, input_setnames[0]);
+ return;
+ }
+ if (!(rset = sset->rset))
+ {
+ zh->errCode = 30;
+ zh->errString = nmem_strdup (nmem, input_setnames[0]);
+ return;
+ }
+ if (strcmp (output_setname, input_setnames[0]))
+ {
+ rset = rset_dup (rset);
+ sset = resultSetAdd (zh, output_setname, 1);
+ sset->rset = rset;
+ }
+ resultSetSortSingle (zh, nmem, sset, rset, sort_sequence, sort_status);
+}
+
+void resultSetSortSingle (ZebraHandle zh, NMEM nmem,
+ ZebraSet sset, RSET rset,
+ Z_SortKeySpecList *sort_sequence, int *sort_status)
+{
+ int i;
+ zint psysno = 0;
+ struct it_key key;
+ struct sortKeyInfo sort_criteria[3];
+ int num_criteria;
+ int term_index;
+ RSFD rfd;
+
+ yaz_log (LOG_LOG, "resultSetSortSingle start");
+ sset->sort_info->num_entries = 0;
+
+ sset->hits = 0;
+ num_criteria = sort_sequence->num_specs;
+ if (num_criteria > 3)
+ num_criteria = 3;
+ for (i = 0; i < num_criteria; i++)
+ {
+ Z_SortKeySpec *sks = sort_sequence->specs[i];
+ Z_SortKey *sk;
+
+ if (*sks->sortRelation == Z_SortKeySpec_ascending)
+ sort_criteria[i].relation = 'A';
+ else if (*sks->sortRelation == Z_SortKeySpec_descending)
+ sort_criteria[i].relation = 'D';
+ else
+ {
+ zh->errCode = 214;
+ return;
+ }
+ if (sks->sortElement->which == Z_SortElement_databaseSpecific)
+ {
+ zh->errCode = 210;
+ return;
+ }
+ else if (sks->sortElement->which != Z_SortElement_generic)
+ {
+ zh->errCode = 237;
+ return;
+ }
+ sk = sks->sortElement->u.generic;
+ switch (sk->which)
+ {
+ case Z_SortKey_sortField:
+ yaz_log (LOG_DEBUG, "Sort: key %d is of type sortField", i+1);
+ zh->errCode = 207;
+ return;
+ case Z_SortKey_elementSpec:
+ yaz_log (LOG_DEBUG, "Sort: key %d is of type elementSpec", i+1);
+ zh->errCode = 207;
+ return;
+ case Z_SortKey_sortAttributes:
+ yaz_log (LOG_DEBUG, "Sort: key %d is of type sortAttributes", i+1);
+ sort_criteria[i].attrUse =
+ zebra_maps_sort (zh->reg->zebra_maps,
+ sk->u.sortAttributes,
+ &sort_criteria[i].numerical);
+ yaz_log (LOG_DEBUG, "use value = %d", sort_criteria[i].attrUse);
+ if (sort_criteria[i].attrUse == -1)
+ {
+ zh->errCode = 116;
+ return;
+ }
+ if (sortIdx_type (zh->reg->sortIdx, sort_criteria[i].attrUse))
+ {
+ zh->errCode = 207;
+ return;
+ }
+ break;
+ }
+ }
+ rfd = rset_open (rset, RSETF_READ);
+ while (rset_read (rset, rfd, &key, &term_index))
+ {
+#if IT_KEY_NEW
+ zint this_sys = key.mem[0];
+#else
+ zint this_sys = key.sysno;
+#endif
+ if (this_sys != psysno)
+ {
+ (sset->hits)++;
+ psysno = this_sys;
+ resultSetInsertSort (zh, sset,
+ sort_criteria, num_criteria, psysno);
+ }
+ }
+ rset_close (rset, rfd);
+
+ for (i = 0; i < rset->no_rset_terms; i++)
+ yaz_log (LOG_LOG, "term=\"%s\" nn=%d type=%s count=%d",
+ rset->rset_terms[i]->name,
+ rset->rset_terms[i]->nn,
+ rset->rset_terms[i]->flags,
+ rset->rset_terms[i]->count);
+
+ *sort_status = Z_SortResponse_success;
+ yaz_log (LOG_LOG, "resultSetSortSingle end");
+}
+
+RSET resultSetRef (ZebraHandle zh, const char *resultSetId)
+{
+ ZebraSet s;
+
+ if ((s = resultSetGet (zh, resultSetId)))
+ return s->rset;
+ return NULL;
+}
+
+void resultSetRank (ZebraHandle zh, ZebraSet zebraSet, RSET rset)
+{
+ zint kno = 0;
+ struct it_key key;
+ RSFD rfd;
+ int term_index, i;
+ ZebraRankClass rank_class;
+ struct rank_control *rc;
+ struct zset_sort_info *sort_info;
+ const char *rank_handler_name = res_get_def(zh->res, "rank", "rank-1");
+ zint cur,tot;
+ zint est=-2; /* -2 not done, -1 can't do, >0 actual estimate*/
+ zint esthits;
+
+ sort_info = zebraSet->sort_info;
+ sort_info->num_entries = 0;
+ zebraSet->hits = 0;
+ rfd = rset_open (rset, RSETF_READ);
+
+ yaz_log (LOG_LOG, "resultSetRank");
+
+ rank_class = zebraRankLookup (zh, rank_handler_name);
+ if (!rank_class)
+ {
+ yaz_log (LOG_WARN, "No such rank handler: %s", rank_handler_name);
+ return;
+ }
+ rc = rank_class->control;
+
+ if (rset_read (rset, rfd, &key, &term_index))
+ {
+#if IT_KEY_NEW
+ zint psysno = key.mem[0];
+#else
+ zint psysno = key.sysno;
+#endif
+ int score;
+ void *handle =
+ (*rc->begin) (zh->reg, rank_class->class_handle, rset);
+ (zebraSet->hits)++;
+ esthits=atoi(res_get_def(zh->res,"estimatehits","0"));
+ if (!esthits) est=-1; /* can not do */
+ do
+ {
+#if IT_KEY_NEW
+ zint this_sys = key.mem[0];
+#else
+ zint this_sys = key.sysno;
+#endif
+ kno++;
+ if (this_sys != psysno)
+ {
+ score = (*rc->calc) (handle, psysno);
+
+ resultSetInsertRank (zh, sort_info, psysno, score, 'A');
+ (zebraSet->hits)++;
+ psysno = this_sys;
+ }
+ (*rc->add) (handle, this_sys, term_index);
+ if ( (est==-2) && (zebraSet->hits==esthits))
+ { /* time to estimate the hits */
+ float f;
+ rset_pos(rset,rfd,&cur,&tot);
+ if (tot>0) {
+ f=1.0*cur/tot;
+ est=(zint)(zebraSet->hits/f);
+ /* FIXME - round the guess to 3 digits */
+ logf(LOG_LOG, "Estimating hits (%s) "
+ ZINT_FORMAT"->%d"
+ "; "ZINT_FORMAT"->"ZINT_FORMAT,
+ rset->control->desc,
+ cur, zebraSet->hits,
+ tot,est);
+ zebraSet->hits=est;