如何使用整数 id 重新索引文档?
How to re-index documents with integer id?
我有 JSON 个表示数据库行的文档。
{"id":3121,"name":"Nikon AF-S DX Nikkor 35 mm", "brand": "Nikon", "price": 456.32}
{"id":3122,"name":"Canon EF-S 55-250 mm", "brand": "Canon", "price": 500.98}
我正在尝试使用 Lucene.NET 为这些文档编制索引。我创建了一个 class 代表这些 JSON 个条目。
[<CLIMutable>]
type Lens =
{ Id: int; Name: string; Brand: string; Price: Float}
我可以打开 JSON 条目将其转换为 Lens 对象,然后创建一个 Lucene 文档。
let getDocument (inputDocument:Lens) =
let id = StoredField("id", inputDocument.Id)
let name = TextField("name", inputDocument.Name, Field.Store.YES)
let brand = StoredField("brand", inputDocument.Brand)
let price = StoredField("price", inputDocument.Price)
let doc = Document()
doc.Add(id)
doc.Add(name)
doc.Add(brand)
doc.Add(price)
// return
doc
这有效,我可以将文档添加到索引并进行搜索。当我想更新索引中的文档而不是添加它时,问题就开始了。
let upsertDocument (writer:IndexWriter) (doc:Document) =
try
let id = doc.GetField("id").GetStringValue()
let term = Term("id", id)
writer.UpdateDocument(term, doc)
writer.Flush(triggerMerge = false, applyAllDeletes = false)
Ok "Ok"
with ex ->
logger
<| sprintf "Exception : %s" ex.Message
logger
<| sprintf "Exception : %A" ex.StackTrace
Error ex.Message
文档说我必须创建一个带有 id 字段的 Term 并将 .GetStringValue() 用于该术语并调用 .UpdateDocument(term, doc)。但是,这不起作用,每次我调用 upsertDocument 时都会添加一个新文档。
int32 数据库 ID 的最佳字段类型是什么?我如何在索引更新操作中使用它来覆盖以前的条目?
单个文件中的完整工作流程:
核心作为要点更好:
https://gist.github.com/l1x/91c36b867acc70e8486a6bce7899332a
Update0:有点好笑。它不会重现错误。
更新 1:我可以可靠地重现该错误。关键是调用 IndexWriter.commit()。通过检查文件可以看到重复。
搜索 Nikon 或 Canon 会得到许多文档。这些都有相同的id。
> searcherz.Search(query, 20).ScoreDocs;;
val it : ScoreDoc [] =
[|doc=5 score=1.1118877 shardIndex=-1 {Doc = 5;
Score = 1.111887693f;
ShardIndex = -1;};
doc=6 score=1.1118877 shardIndex=-1 {Doc = 6;
Score = 1.111887693f;
ShardIndex = -1;};
doc=7 score=1.1118877 shardIndex=-1 {Doc = 7;
Score = 1.111887693f;
ShardIndex = -1;};
doc=8 score=1.1118877 shardIndex=-1 {Doc = 8;
Score = 1.111887693f;
ShardIndex = -1;}|]
重复:
> let hits = searcherz.Search(query, 20).ScoreDocs;;
val hits : ScoreDoc [] =
[|doc=5 score=1.1118877 shardIndex=-1; doc=6 score=1.1118877 shardIndex=-1;
doc=7 score=1.1118877 shardIndex=-1; doc=8 score=1.1118877 shardIndex=-1|]
> hits |> Seq.map (fun hit -> searcherz.Doc(hit.Doc)) |> Seq.map Seq.head;;
val it : seq<IIndexableField> =
seq
[stored<id:3122> {Boost = 1.0f;
FieldType = stored;
IndexableFieldType = stored;
Name = "id";
NumericType = INT32;};
stored<id:3122> {Boost = 1.0f;
FieldType = stored;
IndexableFieldType = stored;
Name = "id";
NumericType = INT32;};
stored<id:3122> {Boost = 1.0f;
FieldType = stored;
IndexableFieldType = stored;
Name = "id";
NumericType = INT32;};
stored<id:3122> {Boost = 1.0f;
FieldType = stored;
IndexableFieldType = stored;
Name = "id";
NumericType = INT32;}]
我不确定这是错误还是功能。
更新2:代码已上传至gist。
好的,我想我明白了。问题是您无法通过使用 GetStringValue
将整数 ID 转换为字符串(例如 "3122"
)来创建有效的 Term
。相反,您必须从 ID 的原始字节(例如 [60 8 0 0 18 31]
)创建术语,如下所示:
open Lucene.Net.Util
let id = doc.GetField("id").GetInt32Value().Value
let bytes = BytesRef(NumericUtils.BUF_SIZE_INT32)
NumericUtils.Int32ToPrefixCodedBytes(id, 0, bytes)
let term = Term("id", bytes)
进行此更改后,我不再在索引中看到重复的文档。有关详细信息,请参阅 this SO question。
我有 JSON 个表示数据库行的文档。
{"id":3121,"name":"Nikon AF-S DX Nikkor 35 mm", "brand": "Nikon", "price": 456.32}
{"id":3122,"name":"Canon EF-S 55-250 mm", "brand": "Canon", "price": 500.98}
我正在尝试使用 Lucene.NET 为这些文档编制索引。我创建了一个 class 代表这些 JSON 个条目。
[<CLIMutable>]
type Lens =
{ Id: int; Name: string; Brand: string; Price: Float}
我可以打开 JSON 条目将其转换为 Lens 对象,然后创建一个 Lucene 文档。
let getDocument (inputDocument:Lens) =
let id = StoredField("id", inputDocument.Id)
let name = TextField("name", inputDocument.Name, Field.Store.YES)
let brand = StoredField("brand", inputDocument.Brand)
let price = StoredField("price", inputDocument.Price)
let doc = Document()
doc.Add(id)
doc.Add(name)
doc.Add(brand)
doc.Add(price)
// return
doc
这有效,我可以将文档添加到索引并进行搜索。当我想更新索引中的文档而不是添加它时,问题就开始了。
let upsertDocument (writer:IndexWriter) (doc:Document) =
try
let id = doc.GetField("id").GetStringValue()
let term = Term("id", id)
writer.UpdateDocument(term, doc)
writer.Flush(triggerMerge = false, applyAllDeletes = false)
Ok "Ok"
with ex ->
logger
<| sprintf "Exception : %s" ex.Message
logger
<| sprintf "Exception : %A" ex.StackTrace
Error ex.Message
文档说我必须创建一个带有 id 字段的 Term 并将 .GetStringValue() 用于该术语并调用 .UpdateDocument(term, doc)。但是,这不起作用,每次我调用 upsertDocument 时都会添加一个新文档。
int32 数据库 ID 的最佳字段类型是什么?我如何在索引更新操作中使用它来覆盖以前的条目?
单个文件中的完整工作流程:
核心作为要点更好:
https://gist.github.com/l1x/91c36b867acc70e8486a6bce7899332a
Update0:有点好笑。它不会重现错误。
更新 1:我可以可靠地重现该错误。关键是调用 IndexWriter.commit()。通过检查文件可以看到重复。
搜索 Nikon 或 Canon 会得到许多文档。这些都有相同的id。
> searcherz.Search(query, 20).ScoreDocs;;
val it : ScoreDoc [] =
[|doc=5 score=1.1118877 shardIndex=-1 {Doc = 5;
Score = 1.111887693f;
ShardIndex = -1;};
doc=6 score=1.1118877 shardIndex=-1 {Doc = 6;
Score = 1.111887693f;
ShardIndex = -1;};
doc=7 score=1.1118877 shardIndex=-1 {Doc = 7;
Score = 1.111887693f;
ShardIndex = -1;};
doc=8 score=1.1118877 shardIndex=-1 {Doc = 8;
Score = 1.111887693f;
ShardIndex = -1;}|]
重复:
> let hits = searcherz.Search(query, 20).ScoreDocs;;
val hits : ScoreDoc [] =
[|doc=5 score=1.1118877 shardIndex=-1; doc=6 score=1.1118877 shardIndex=-1;
doc=7 score=1.1118877 shardIndex=-1; doc=8 score=1.1118877 shardIndex=-1|]
> hits |> Seq.map (fun hit -> searcherz.Doc(hit.Doc)) |> Seq.map Seq.head;;
val it : seq<IIndexableField> =
seq
[stored<id:3122> {Boost = 1.0f;
FieldType = stored;
IndexableFieldType = stored;
Name = "id";
NumericType = INT32;};
stored<id:3122> {Boost = 1.0f;
FieldType = stored;
IndexableFieldType = stored;
Name = "id";
NumericType = INT32;};
stored<id:3122> {Boost = 1.0f;
FieldType = stored;
IndexableFieldType = stored;
Name = "id";
NumericType = INT32;};
stored<id:3122> {Boost = 1.0f;
FieldType = stored;
IndexableFieldType = stored;
Name = "id";
NumericType = INT32;}]
我不确定这是错误还是功能。
更新2:代码已上传至gist。
好的,我想我明白了。问题是您无法通过使用 GetStringValue
将整数 ID 转换为字符串(例如 "3122"
)来创建有效的 Term
。相反,您必须从 ID 的原始字节(例如 [60 8 0 0 18 31]
)创建术语,如下所示:
open Lucene.Net.Util
let id = doc.GetField("id").GetInt32Value().Value
let bytes = BytesRef(NumericUtils.BUF_SIZE_INT32)
NumericUtils.Int32ToPrefixCodedBytes(id, 0, bytes)
let term = Term("id", bytes)
进行此更改后,我不再在索引中看到重复的文档。有关详细信息,请参阅 this SO question。