最近在做关于结构化及非结构化数据混合索引及搜索的工作,其中有一项挑战是根据论文中的数据集、标签集,自己得到真值集(不知道为啥论文没给出真值集),然后进行后续工作。
在此过程中,我需要知道真值集的存储格式——ivecs。
ivecs与fvecs格式
在常用的公开数据集中(如Crawl、Enron),数据集文件、查询文件往往使用fvecs格式存储。而真值集(即查询的答案)文件使用ivecs格式存储。其实这两种格式十分相似。
fvecs
数据集、查询集采用fvecs格式,其实他们是完全相同的东西。在数据集中,存储的是所有向量,而查询集中,存储的同样是向量,只是向量数量会少一些。
fvecs采用二进制来存储,直接打开便是乱码。
下面用一张图来表示fvecs的大致格式:
每一“行”中,第一个数表示数据的维度dim,后面跟着的dim个数便是向量各维度的值。(注:fvecs中的f指float32)
因此,一“行”表示的便是一个向量。
那么行数是如何计算的呢?我们一般使用下面的式子:
line_num = filesize / (dim + 1 ) / 4
其中line_num
是行数,filesize
是文件字节数,dim+1
指每个向量占用的数值个数,4
指每4个字节存储一个数值。
ivecs
ivecs其实和fvecs的格式是一样的,只不过它存储的不是向量,而是每一条查询的答案。
就是说,ivecs里的每一“行”里,第一个数据是查询答案的数量n,后面n个数是答案向量的id。(注:ivecs中的i指int32)
cpp读取fvecs文件代码
先将下面的代码放入read.cpp,然后编译出read.exe
#include <fstream>
#include <vector>
#include<iostream>
using namespace std;
void load_ivecs_data(const char* filename,
std::vector<std::vector<float> >& results, unsigned &num, unsigned &dim) {
std::ifstream in(filename, std::ios::binary);
if (!in.is_open()) {
std::cout << "open file error" << std::endl;
exit(-1);
}
in.read((char *)&dim, 4);
in.seekg(0, std::ios::end);
std::ios::pos_type ss = in.tellg();
size_t fsize = (size_t)ss;
num = (unsigned)(fsize / (dim + 1) / 4);
results.resize(num);
for (unsigned i = 0; i < num; i++) results[i].resize(dim);
in.seekg(0, std::ios::beg);
for (size_t i = 0; i < num; i++) {
in.seekg(4, std::ios::cur);
in.read((char*)results[i].data(), dim * 4);
}
in.close();
}
int main(int argc, char** argv) {
std::vector<std::vector<float> > true_load;
unsigned dim, num;
load_ivecs_data(argv[1], true_load, num, dim);
std::cout << "result_num:"<< num << std::endl << "result dimension:" << dim << std::endl;
for(size_t i = 0; i < num; i++) {
for(size_t j = 0; j < dim; j++) {
std::cout << true_load[i][j] << " ";
}
std::cout << std::endl;
}
std::cout << "result_num:"<< num << std::endl << "result dimension:" << dim << std::endl;
return 0;
}
在read.exe所在目录下放置groundtruth数据集文件,然后在cmd中输入:
.\read.exe .\xzx_groundtruth
结果如下:
补档:python读取ivecs、fvecs代码
import sys
import numpy as np
def ivecs_read(fname):
a = np.fromfile(fname, dtype='int32')
d = a[0]
return a.reshape(-1, d + 1)[:, 1:].copy()
def fvecs_read(fname):
return ivecs_read(fname).view('float32')
dataset_path = sys.argv[1]
dataset = fvecs_read(dataset_path)