float
ReqOptMatcher_Score_IMP(RequiredOptionalMatcher *self) {
    RequiredOptionalMatcherIVARS *const ivars = ReqOptMatcher_IVARS(self);
    int32_t const current_doc = Matcher_Get_Doc_ID(ivars->req_matcher);

    if (ivars->opt_matcher_first_time) {
        ivars->opt_matcher_first_time = false;
        if (ivars->opt_matcher != NULL
            && !Matcher_Advance(ivars->opt_matcher, current_doc)) {
            DECREF(ivars->opt_matcher);
            ivars->opt_matcher = NULL;
        }
    }

    if (ivars->opt_matcher == NULL) {
        return Matcher_Score(ivars->req_matcher) * ivars->coord_factors[1];
    }
    else {
        int32_t opt_matcher_doc = Matcher_Get_Doc_ID(ivars->opt_matcher);

        if (opt_matcher_doc < current_doc) {
            opt_matcher_doc = Matcher_Advance(ivars->opt_matcher, current_doc);
            if (!opt_matcher_doc) {
                DECREF(ivars->opt_matcher);
                ivars->opt_matcher = NULL;
                float req_score = Matcher_Score(ivars->req_matcher);
                return req_score * ivars->coord_factors[1];
            }
        }

        if (opt_matcher_doc == current_doc) {
            float score = Matcher_Score(ivars->req_matcher)
                          + Matcher_Score(ivars->opt_matcher);
            score *= ivars->coord_factors[2];
            return score;
        }
        else {
            return Matcher_Score(ivars->req_matcher) * ivars->coord_factors[1];
        }
    }
}
Exemple #2
0
static int32_t
S_advance_after_current(ORScorer *self, ORScorerIVARS *ivars) {
    float *const     scores = ivars->scores;
    Matcher *child;

    // Get the top Matcher, or bail because there are no Matchers left.
    if (!ivars->size) { return 0; }
    else              { child = ivars->top_hmd->matcher; }

    // The top matcher will already be at the correct doc, so start there.
    ivars->doc_id        = ivars->top_hmd->doc;
    scores[0]            = Matcher_Score(child);
    ivars->matching_kids = 1;

    do {
        // Attempt to advance past current doc.
        int32_t top_doc_id
            = SI_top_next((ORMatcher*)self, (ORMatcherIVARS*)ivars);
        if (!top_doc_id) {
            if (!ivars->size) {
                break; // bail, no more to advance
            }
        }

        if (top_doc_id != ivars->doc_id) {
            // Bail, least doc in queue is now past the one we're scoring.
            break;
        }
        else {
            // Accumulate score.
            child = ivars->top_hmd->matcher;
            scores[ivars->matching_kids] = Matcher_Score(child);
            ivars->matching_kids++;
        }
    } while (true);

    return ivars->doc_id;
}
Exemple #3
0
static INLINE bool
SI_competitive(SortCollectorIVARS *ivars, int32_t doc_id) {
    /* Ordinarily, we would cache local copies of more member variables in
     * const automatic variables in order to improve code clarity and provide
     * more hints to the compiler about what variables are actually invariant
     * for the duration of this routine:
     *
     *     uint8_t *const actions    = ivars->actions;
     *     const uint32_t num_rules  = ivars->num_rules;
     *     const int32_t bubble_doc = ivars->bubble_doc;
     *
     * However, our major goal is to return as quickly as possible, and the
     * common case is that we'll have our answer before the first loop iter
     * finishes -- so we don't worry about the cost of performing extra
     * dereferencing on subsequent loop iters.
     *
     * The goal of returning quickly also drives the choice of a "do-while"
     * loop instead of a "for" loop, and the switch statement optimized for
     * compilation to a jump table.
     */
    uint8_t *const actions = ivars->actions;
    uint32_t i = 0;

    // Iterate through our array of actions, returning as quickly as possible.
    do {
        switch (actions[i] & ACTIONS_MASK) {
            case AUTO_ACCEPT:
                return true;
            case AUTO_REJECT:
                return false;
            case AUTO_TIE:
                break;
            case COMPARE_BY_SCORE: {
                    float score = Matcher_Score(ivars->matcher);
                    if (*(int32_t*)&score == *(int32_t*)&ivars->bubble_score) {
                        break;
                    }
                    if (score > ivars->bubble_score) {
                        MatchDoc_IVARS(ivars->bumped)->score = score;
                        return true;
                    }
                    else if (score < ivars->bubble_score) {
                        return false;
                    }
                }
                break;
            case COMPARE_BY_SCORE_REV: {
                    float score = Matcher_Score(ivars->matcher);
                    if (*(int32_t*)&score == *(int32_t*)&ivars->bubble_score) {
                        break;
                    }
                    if (score < ivars->bubble_score) {
                        MatchDoc_IVARS(ivars->bumped)->score = score;
                        return true;
                    }
                    else if (score > ivars->bubble_score) {
                        return false;
                    }
                }
                break;
            case COMPARE_BY_DOC_ID:
                if (doc_id > ivars->bubble_doc)      { return false; }
                else if (doc_id < ivars->bubble_doc) { return true; }
                break;
            case COMPARE_BY_DOC_ID_REV:
                if (doc_id > ivars->bubble_doc)      { return true; }
                else if (doc_id < ivars->bubble_doc) { return false; }
                break;
            case COMPARE_BY_ORD1: {
                    int32_t comparison
                        = SI_compare_by_ord1(
                              ivars, i, SI_validate_doc_id(ivars, doc_id),
                              ivars->bubble_doc);
                    if (comparison < 0)      { return true; }
                    else if (comparison > 0) { return false; }
                }
                break;
            case COMPARE_BY_ORD1_REV: {
                    int32_t comparison
                        = SI_compare_by_ord1(
                              ivars, i, ivars->bubble_doc,
                              SI_validate_doc_id(ivars, doc_id));
                    if (comparison < 0)      { return true; }
                    else if (comparison > 0) { return false; }
                }
                break;
            case COMPARE_BY_ORD2: {
                    int32_t comparison
                        = SI_compare_by_ord2(
                              ivars, i, SI_validate_doc_id(ivars, doc_id),
                              ivars->bubble_doc);
                    if (comparison < 0)      { return true; }
                    else if (comparison > 0) { return false; }
                }
                break;
            case COMPARE_BY_ORD2_REV: {
                    int32_t comparison
                        = SI_compare_by_ord2(
                              ivars, i, ivars->bubble_doc,
                              SI_validate_doc_id(ivars, doc_id));
                    if (comparison < 0)      { return true; }
                    else if (comparison > 0) { return false; }
                }
                break;
            case COMPARE_BY_ORD4: {
                    int32_t comparison
                        = SI_compare_by_ord4(
                              ivars, i, SI_validate_doc_id(ivars, doc_id),
                              ivars->bubble_doc);
                    if (comparison < 0)      { return true; }
                    else if (comparison > 0) { return false; }
                }
                break;
            case COMPARE_BY_ORD4_REV: {
                    int32_t comparison
                        = SI_compare_by_ord4(
                              ivars, i, ivars->bubble_doc,
                              SI_validate_doc_id(ivars, doc_id));
                    if (comparison < 0)      { return true; }
                    else if (comparison > 0) { return false; }
                }
                break;
            case COMPARE_BY_ORD8: {
                    int32_t comparison
                        = SI_compare_by_ord8(
                              ivars, i, SI_validate_doc_id(ivars, doc_id),
                              ivars->bubble_doc);
                    if (comparison < 0)      { return true; }
                    else if (comparison > 0) { return false; }
                }
                break;
            case COMPARE_BY_ORD8_REV: {
                    int32_t comparison
                        = SI_compare_by_ord8(
                              ivars, i, ivars->bubble_doc,
                              SI_validate_doc_id(ivars, doc_id));
                    if (comparison < 0)      { return true; }
                    else if (comparison > 0) { return false; }
                }
                break;
            case COMPARE_BY_ORD16: {
                    int32_t comparison
                        = SI_compare_by_ord16(
                              ivars, i, SI_validate_doc_id(ivars, doc_id),
                              ivars->bubble_doc);
                    if (comparison < 0)      { return true; }
                    else if (comparison > 0) { return false; }
                }
                break;
            case COMPARE_BY_ORD16_REV: {
                    int32_t comparison
                        = SI_compare_by_ord16(
                              ivars, i, ivars->bubble_doc,
                              SI_validate_doc_id(ivars, doc_id));
                    if (comparison < 0)      { return true; }
                    else if (comparison > 0) { return false; }
                }
                break;
            case COMPARE_BY_ORD32: {
                    int32_t comparison
                        = SI_compare_by_ord32(
                              ivars, i, SI_validate_doc_id(ivars, doc_id),
                              ivars->bubble_doc);
                    if (comparison < 0)      { return true; }
                    else if (comparison > 0) { return false; }
                }
                break;
            case COMPARE_BY_ORD32_REV: {
                    int32_t comparison
                        = SI_compare_by_ord32(
                              ivars, i, ivars->bubble_doc,
                              SI_validate_doc_id(ivars, doc_id));
                    if (comparison < 0)      { return true; }
                    else if (comparison > 0) { return false; }
                }
                break;
            case COMPARE_BY_NATIVE_ORD16: {
                    int32_t comparison
                        = SI_compare_by_native_ord16(
                              ivars, i, SI_validate_doc_id(ivars, doc_id),
                              ivars->bubble_doc);
                    if (comparison < 0)      { return true; }
                    else if (comparison > 0) { return false; }
                }
                break;
            case COMPARE_BY_NATIVE_ORD16_REV: {
                    int32_t comparison
                        = SI_compare_by_native_ord16(
                              ivars, i, ivars->bubble_doc,
                              SI_validate_doc_id(ivars, doc_id));
                    if (comparison < 0)      { return true; }
                    else if (comparison > 0) { return false; }
                }
                break;
            case COMPARE_BY_NATIVE_ORD32: {
                    int32_t comparison
                        = SI_compare_by_native_ord32(
                              ivars, i, SI_validate_doc_id(ivars, doc_id),
                              ivars->bubble_doc);
                    if (comparison < 0)      { return true; }
                    else if (comparison > 0) { return false; }
                }
                break;
            case COMPARE_BY_NATIVE_ORD32_REV: {
                    int32_t comparison
                        = SI_compare_by_native_ord32(
                              ivars, i, ivars->bubble_doc,
                              SI_validate_doc_id(ivars, doc_id));
                    if (comparison < 0)      { return true; }
                    else if (comparison > 0) { return false; }
                }
                break;
            default:
                THROW(ERR, "UNEXPECTED action %u8", actions[i]);
        }
    } while (++i < ivars->num_actions);

    // If we've made it this far and we're still tied, reject the doc so that
    // we prefer items already in the queue.  This has the effect of
    // implicitly breaking ties by doc num, since docs are collected in order.
    return false;
}
Exemple #4
0
void
SortColl_collect(SortCollector *self, int32_t doc_id) {
    SortCollectorIVARS *const ivars = SortColl_IVARS(self);

    // Add to the total number of hits.
    ivars->total_hits++;

    // Collect this hit if it's competitive.
    if (SI_competitive(ivars, doc_id)) {
        MatchDoc *const match_doc = ivars->bumped;
        MatchDocIVARS *const match_doc_ivars = MatchDoc_IVARS(match_doc);
        match_doc_ivars->doc_id = doc_id + ivars->base;

        if (ivars->need_score && match_doc_ivars->score == F32_NEGINF) {
            match_doc_ivars->score = Matcher_Score(ivars->matcher);
        }

        // Fetch values so that cross-segment sorting can work.
        if (ivars->need_values) {
            VArray *values = match_doc_ivars->values;

            for (uint32_t i = 0, max = ivars->num_rules; i < max; i++) {
                SortCache *cache   = ivars->sort_caches[i];
                Obj       *old_val = (Obj*)VA_Delete(values, i);
                if (cache) {
                    int32_t ord = SortCache_Ordinal(cache, doc_id);
                    Obj *blank = old_val
                                 ? old_val
                                 : SortCache_Make_Blank(cache);
                    Obj *val = SortCache_Value(cache, ord, blank);
                    if (val) { VA_Store(values, i, (Obj*)val); }
                    else     { DECREF(blank); }
                }
            }
        }

        // Insert the new MatchDoc.
        ivars->bumped = (MatchDoc*)HitQ_Jostle(ivars->hit_q, (Obj*)match_doc);

        if (ivars->bumped) {
            if (ivars->bumped == match_doc) {
                /* The queue is full, and we have established a threshold for
                 * this segment as to what sort of document is definitely not
                 * acceptable.  Turn off AUTO_ACCEPT and start actually
                 * testing whether hits are competitive. */
                ivars->bubble_score  = match_doc_ivars->score;
                ivars->bubble_doc    = doc_id;
                ivars->actions       = ivars->derived_actions;
            }

            // Recycle.
            MatchDoc_IVARS(ivars->bumped)->score = ivars->need_score
                                                   ? F32_NEGINF
                                                   : F32_NAN;
        }
        else {
            // The queue isn't full yet, so create a fresh MatchDoc.
            VArray *values = ivars->need_values
                             ? VA_new(ivars->num_rules)
                             : NULL;
            float fake_score = ivars->need_score ? F32_NEGINF : F32_NAN;
            ivars->bumped = MatchDoc_new(INT32_MAX, fake_score, values);
            DECREF(values);
        }

    }
}