void SortColl_set_reader(SortCollector *self, SegReader *reader) { SortCollectorIVARS *const ivars = SortColl_IVARS(self); SortReader *sort_reader = (SortReader*)SegReader_Fetch(reader, VTable_Get_Name(SORTREADER)); // Reset threshold variables and trigger auto-action behavior. MatchDocIVARS *const bumped_ivars = MatchDoc_IVARS(ivars->bumped); bumped_ivars->doc_id = INT32_MAX; ivars->bubble_doc = INT32_MAX; bumped_ivars->score = ivars->need_score ? F32_NEGINF : F32_NAN; ivars->bubble_score = ivars->need_score ? F32_NEGINF : F32_NAN; ivars->actions = ivars->auto_actions; // Obtain sort caches. Derive actions array for this segment. if (ivars->need_values && sort_reader) { for (uint32_t i = 0, max = ivars->num_rules; i < max; i++) { SortRule *rule = (SortRule*)VA_Fetch(ivars->rules, i); CharBuf *field = SortRule_Get_Field(rule); SortCache *cache = field ? SortReader_Fetch_Sort_Cache(sort_reader, field) : NULL; ivars->sort_caches[i] = cache; ivars->derived_actions[i] = S_derive_action(rule, cache); if (cache) { ivars->ord_arrays[i] = SortCache_Get_Ords(cache); } else { ivars->ord_arrays[i] = NULL; } } } ivars->seg_doc_max = reader ? SegReader_Doc_Max(reader) : 0; Coll_set_reader((Collector*)self, reader); }
HitQueue* HitQ_init(HitQueue *self, Schema *schema, SortSpec *sort_spec, uint32_t wanted) { HitQueueIVARS *const ivars = HitQ_IVARS(self); if (sort_spec) { VArray *rules = SortSpec_Get_Rules(sort_spec); uint32_t num_rules = VA_Get_Size(rules); uint32_t action_num = 0; if (!schema) { THROW(ERR, "Can't supply sort_spec without schema"); } ivars->need_values = false; ivars->num_actions = num_rules; ivars->actions = (uint8_t*)MALLOCATE(num_rules * sizeof(uint8_t)); ivars->field_types = (FieldType**)CALLOCATE(num_rules, sizeof(FieldType*)); for (uint32_t i = 0; i < num_rules; i++) { SortRule *rule = (SortRule*)VA_Fetch(rules, i); int32_t rule_type = SortRule_Get_Type(rule); bool reverse = SortRule_Get_Reverse(rule); if (rule_type == SortRule_SCORE) { ivars->actions[action_num++] = reverse ? COMPARE_BY_SCORE_REV : COMPARE_BY_SCORE; } else if (rule_type == SortRule_DOC_ID) { ivars->actions[action_num++] = reverse ? COMPARE_BY_DOC_ID_REV : COMPARE_BY_DOC_ID; } else if (rule_type == SortRule_FIELD) { String *field = SortRule_Get_Field(rule); FieldType *type = Schema_Fetch_Type(schema, field); if (type) { ivars->field_types[action_num] = (FieldType*)INCREF(type); ivars->actions[action_num++] = reverse ? COMPARE_BY_VALUE_REV : COMPARE_BY_VALUE; ivars->need_values = true; } else { // Skip over fields we don't know how to sort on. continue; } } else { THROW(ERR, "Unknown SortRule type: %i32", rule_type); } } } else { ivars->num_actions = 2; ivars->actions = (uint8_t*)MALLOCATE(ivars->num_actions * sizeof(uint8_t)); ivars->actions[0] = COMPARE_BY_SCORE; ivars->actions[1] = COMPARE_BY_DOC_ID; } return (HitQueue*)PriQ_init((PriorityQueue*)self, wanted); }
SortCollector* SortColl_init(SortCollector *self, Schema *schema, SortSpec *sort_spec, uint32_t wanted) { VArray *rules = sort_spec ? (VArray*)INCREF(SortSpec_Get_Rules(sort_spec)) : S_default_sort_rules(); uint32_t num_rules = VA_Get_Size(rules); // Validate. if (sort_spec && !schema) { THROW(ERR, "Can't supply a SortSpec without a Schema."); } if (!num_rules) { THROW(ERR, "Can't supply a SortSpec with no SortRules."); } // Init. Coll_init((Collector*)self); SortCollectorIVARS *const ivars = SortColl_IVARS(self); ivars->total_hits = 0; ivars->bubble_doc = INT32_MAX; ivars->bubble_score = F32_NEGINF; ivars->seg_doc_max = 0; // Assign. ivars->wanted = wanted; // Derive. ivars->hit_q = HitQ_new(schema, sort_spec, wanted); ivars->rules = rules; // absorb refcount. ivars->num_rules = num_rules; ivars->sort_caches = (SortCache**)CALLOCATE(num_rules, sizeof(SortCache*)); ivars->ord_arrays = (void**)CALLOCATE(num_rules, sizeof(void*)); ivars->actions = (uint8_t*)CALLOCATE(num_rules, sizeof(uint8_t)); // Build up an array of "actions" which we will execute during each call // to Collect(). Determine whether we need to track scores and field // values. ivars->need_score = false; ivars->need_values = false; for (uint32_t i = 0; i < num_rules; i++) { SortRule *rule = (SortRule*)VA_Fetch(rules, i); int32_t rule_type = SortRule_Get_Type(rule); ivars->actions[i] = S_derive_action(rule, NULL); if (rule_type == SortRule_SCORE) { ivars->need_score = true; } else if (rule_type == SortRule_FIELD) { CharBuf *field = SortRule_Get_Field(rule); FieldType *type = Schema_Fetch_Type(schema, field); if (!type || !FType_Sortable(type)) { THROW(ERR, "'%o' isn't a sortable field", field); } ivars->need_values = true; } } // Perform an optimization. So long as we always collect docs in // ascending order, Collect() will favor lower doc numbers -- so we may // not need to execute a final COMPARE_BY_DOC_ID action. ivars->num_actions = num_rules; if (ivars->actions[num_rules - 1] == COMPARE_BY_DOC_ID) { ivars->num_actions--; } // Override our derived actions with an action which will be excecuted // autmatically until the queue fills up. ivars->auto_actions = (uint8_t*)MALLOCATE(1); ivars->auto_actions[0] = wanted ? AUTO_ACCEPT : AUTO_REJECT; ivars->derived_actions = ivars->actions; ivars->actions = ivars->auto_actions; // Prepare a MatchDoc-in-waiting. VArray *values = ivars->need_values ? VA_new(num_rules) : NULL; float score = ivars->need_score ? F32_NEGINF : F32_NAN; ivars->bumped = MatchDoc_new(INT32_MAX, score, values); DECREF(values); return self; }