lucene文档编号是内部定义的。
每个段内是按0....N一直累加取值(按文档添加顺序分配),当段与段之间合并,那么当前段的文档编号会加上偏移值(在上一个段的基础上,比如原0...M,加上偏移为N+1....M+N);
我在用Lucene的时候有一个问题,我从数据库取数据,我和前台的约定就是基于数据库ID值的,也就是我检索的结果返回的是数据库ID而不是lucene的ID(前台才不知道Lucene),因为lucene现行的结构,就必须加上一个映射表,将lucene的ID映射到数据库ID。不过问题是:
1.多存储了一个ID序列,比如1000万个int32_t,还不能差分编码,因为随机访问。
2.有独立的另外一套条件系统,会和Lucene做合并操作,但是此系统也是以数据库ID驱动的,由于在检索过程中两个系统求交集,因此在检索过程中必须一致映射ID。
所以一直想:可否直接用自定义的ID取代Lucene呢?
问了一些朋友,大家的意思是:不行。
不过本人本着纯属瞎折腾的目的还是做了尝试:
新增加函数
void DocumentWriter::writePostings(int32_t docID,Posting** postings, const int32_t postingsLength, const char* segment)
此函数的原型是
void DocumentWriter::writePostings(Posting** postings, const int32_t postingsLength, const char* segment)
并没有传入ID值,因为使用的是LUCENE内部(分配的)ID,此ID值对于每个内存文档来说都是0值,那么岂不是重复?在合并时,合并的段会加上前一个段的文档数作为偏移,则第一个段依旧是0….m1,第二个段的0…m2会加上偏移m1值使得段文档为m1…m1+m2
1.传入文档编号(暂时改动)
void DocumentWriter::addDocument(const char* segment, Document* doc)
调用改为:
writePostings(docID,postings,postingsLength, segment);
传入文档编号值
2.直接写入文档编号,不使用内部ID值
// modified by lxp
int32_t docCode = docID << 1 ; //写入自定义的文档ID
if (postingFreq == 1)
{
// optimize freq=1
freq->writeVInt(docCode|1); // set low bit of doc num.
}
else
{
freq->writeVInt(docCode); // the document number
freq->writeVInt(postingFreq); // frequency in doc
}
原代码是
//if (postingFreq == 1) // optimize freq=1
// freq->writeVInt(1); // set low bit of doc num.
//else
//{
// freq->writeVInt(0); // the document number
// freq->writeVInt(postingFreq); // frequency in doc
//}
3. 取消偏移量
int32_t SegmentMerger::appendPostings(SegmentMergeInfo** smis)中
去掉以下语句
不用在段的基础上添加偏移值,直接使用自定义ID
// doc += base;
那么检索出来的ID就是自定义的ID
不过这样做当然有问题的:
就是norm是针对0....N的映射表,换而言之,对已一个ID=i(i=0....N),可以直接取其norm值,现在不行了。
因为是自定义的,所以随机不连续。
我再考虑一下这块如何改。
不过呢:
1.数据库设计的时候尽量有序且取值在一个区间内。
2.由于排序因子多:比如重要系数,竞价系数等影响排序的因素多,我思考独立的抽取因子序列。