/**
* 检索文档
* @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;
}