index倒排拉链的查询和merge

/**
 * 检索文档
 * @param[in] env 存储着应用程序运行环境的结构体
 * @param[in,out] results 检索结果
 * @param[in] tokens 从查询中提取出的词元信息
 */
void
search_docs(wiser_env *env, search_results **results,
            query_token_hash *tokens)
{
    int n_tokens;
    doc_search_cursor *cursors;

    if (!tokens) { return; }

    /* 按照文档频率的升序对tokens排序 */
    HASH_SORT(tokens, query_token_value_docs_count_desc_sort);

    /* 初始化 */
    n_tokens = HASH_COUNT(tokens);
    if (n_tokens &&
        (cursors = (doc_search_cursor *) calloc(
                sizeof(doc_search_cursor), n_tokens)))
    {
        int i;
        doc_search_cursor *cur;
        query_token_value *token;
        for (i = 0, token = tokens; token; i++, token = token->hh.next)
        {
            if (!token->token_id)
            {
                /* 当前的token在构建索引的过程中从未出现过 */
                goto exit;
            }
            if (fetch_postings(env, token->token_id,
                               &cursors[i].documents, NULL))
            {
                print_error("decode postings error!: %d\n", token->token_id);
                goto exit;
            }
            if (!cursors[i].documents)
            {
                /* 虽然当前的token存在,但是由于更新或删除导致其倒排列表为空 */
                goto exit;
            }
            cursors[i].current = cursors[i].documents;
        }
        while (cursors[0].current)
        {
            int doc_id, next_doc_id = 0;
            /* 将拥有文档最少的词元称作A */
            doc_id = cursors[0].current->document_id;
            /* 对于除词元A以外的词元,不断获取其下一个document_id,直到当前的document_id不小于词元A的document_id为止 */
            for (cur = cursors + 1, i = 1; i < n_tokens; cur++, i++)
            {
                while (cur->current && cur->current->document_id < doc_id)
                {
                    cur->current = cur->current->next;
                }
                if (!cur->current) { goto exit; }
                /* 对于除词元A以外的词元,如果其document_id不等于词元A的document_id,*/
                /* 那么就将这个document_id设定为next_doc_id */
                if (cur->current->document_id != doc_id)
                {
                    next_doc_id = cur->current->document_id;
                    break;
                }
            }
            if (next_doc_id > 0)
            {
                /* 不断获取A的下一个document_id,直到其当前的document_id不小于next_doc_id为止 */
                while (cursors[0].current
                       && cursors[0].current->document_id < next_doc_id)
                {
                    cursors[0].current = cursors[0].current->next;
                }
            }
            else
            {
                int phrase_count = -1;
                if (env->enable_phrase_search)
                {
                    phrase_count = search_phrase(tokens, cursors);
                }
                if (phrase_count)
                {
                    double score = calc_tf_idf(tokens, cursors, n_tokens,
                                               env->indexed_count);
                    add_search_result(results, doc_id, score);
                }
                cursors[0].current = cursors[0].current->next;
            }
        }
        exit:
        for (i = 0; i < n_tokens; i++)
        {
            if (cursors[i].documents)
            {
                free_token_positions_list(cursors[i].documents);
            }
        }
        free(cursors);
    }
    free_inverted_index(tokens);

    HASH_SORT(*results, search_results_score_desc_sort);
}

前提对token(按照文档数量从小到大排序),倒排拉链按照doc_id大小从小到大排序

1.将token按照文档数量进行排序

2.按照token[0]的倒排拉链进行便利,先使用第一个token[0]的第一个doc_id,

2.1对后面的token进行判断,找到不小于token[0]的doc_id的位置

2.2.1找到不小于doc_id的doc_id后,判断下找到的doc_id和token[0]的doc_id是否匹配,如果不匹配则将该doc_id设置为next_doc_id

2.2.2如果next_doc_id存在则将token[0]的doc_id调整到不小于next_doc_id的位置

2.2如果所有的token的都存在和token[0]相等的doc_id,则该doc_id符合求交接

#include <iostream>
#include <vector>
#include <list>

using namespace std;

int main() {
    std::vector<int> result; // 存放交集doc_id
    std::vector<std::list<int>> docs; // 每个token对应的doc_id列表
    std::vector<std::list<int>::iterator> docs_iterators; // 存储每个token对应doc_id列表的遍历的指针
    // 第一个token对应的doc_id的游标
    while (docs_iterators[0] != docs[0].end()) {
        int doc_id = *(docs_iterators)[0];
        int next_doc_id = 0;
        // 遍历后面所有的
        for (int i = 1; i < docs_iterators.size(); ++i) {
            while (docs_iterators[i] != docs[i].end() && doc_id > *(docs_iterators[i])) {
                ++docs_iterators[i];
            }
            if (docs_iterators[i] == docs[i].end()) {
                // 结束了
                return 0;
            }
            if (doc_id != *(docs_iterators[i])) {
                break;
            }
        }
        if (next_doc_id != 0) {
            while (docs_iterators[0] != docs[0].end() && next_doc_id > (*docs_iterators[0])) {
                ++docs_iterators[0];
            }
        } else {
            ++docs_iterators[0];
            // 存储结果
            result.push_back(*(docs_iterators[0]));
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/INGNIGHT/article/details/132859933