TopDocs* PolySearcher_Top_Docs_IMP(PolySearcher *self, Query *query, uint32_t num_wanted, SortSpec *sort_spec) { PolySearcherIVARS *const ivars = PolySearcher_IVARS(self); Schema *schema = PolySearcher_Get_Schema(self); VArray *searchers = ivars->searchers; I32Array *starts = ivars->starts; HitQueue *hit_q = sort_spec ? HitQ_new(schema, sort_spec, num_wanted) : HitQ_new(NULL, NULL, num_wanted); uint32_t total_hits = 0; Compiler *compiler = Query_Is_A(query, COMPILER) ? ((Compiler*)INCREF(query)) : Query_Make_Compiler(query, (Searcher*)self, Query_Get_Boost(query), false); for (uint32_t i = 0, max = VA_Get_Size(searchers); i < max; i++) { Searcher *searcher = (Searcher*)VA_Fetch(searchers, i); int32_t base = I32Arr_Get(starts, i); TopDocs *top_docs = Searcher_Top_Docs(searcher, (Query*)compiler, num_wanted, sort_spec); VArray *sub_match_docs = TopDocs_Get_Match_Docs(top_docs); total_hits += TopDocs_Get_Total_Hits(top_docs); S_modify_doc_ids(sub_match_docs, base); for (uint32_t j = 0, jmax = VA_Get_Size(sub_match_docs); j < jmax; j++) { MatchDoc *match_doc = (MatchDoc*)VA_Fetch(sub_match_docs, j); if (!HitQ_Insert(hit_q, INCREF(match_doc))) { break; } } DECREF(top_docs); } VArray *match_docs = HitQ_Pop_All(hit_q); TopDocs *retval = TopDocs_new(match_docs, total_hits); DECREF(match_docs); DECREF(compiler); DECREF(hit_q); return retval; }
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; }