上一集当中我们完成了Lucene基本操作中的Create与Read,这一集会将CRUD中的Update与Delete的操作方法告诉你,并且本集会着重於讲解关於"Norms"与权重(Boost)在Lucene中的使用操作。
对於Lucene还没有一些基本认识的朋友,建议先回到上一篇文章中阅读呦!
更新其实就是将存在的索引删除并重新建立Document,不存在的则直接新增。
首先准备一组资料准备更新
List<Product> GetUpdateProductsInformation()
{
return new List<Product>
{
new Product{ Id = 6, Name = "香蕉", Description = "运动完後吃根香蕉补充养分。"},
new Product{ Id = 2, Name = "橘子", Description = "橘子跟柳丁你分得出来吗?"}
};
}
欲更新的Document必须与创建所引时使用的Document栏位相同
void Update(string key, List<Product> information, DirectoryInfo dir, StandardAnalyzer analyzer)
{
using( var directory = FSDirectory.Open(dir))
{
using(var indexWriter = new IndexWriter(directory, analyzer, false, IndexWriter.MaxFieldLength.LIMITED))
{
foreach (var index in information)
{
var document = new Document();
document.Add(new Field("Id", index.Id.ToString(), Field.Store.YES, Field.Index.NO));
document.Add(new Field("Name", index.Name, Field.Store.YES, Field.Index.ANALYZED));
document.Add(new Field("Description", index.Description, Field.Store.YES, Field.Index.ANALYZED));
indexWriter.UpdateDocument(new Term("Name", key) ,document);
}
}
}
}
来测试看看
可以看见 Name = 橘子 的索引已经改为我们新准备的资料罗。
再来是删除!
与更新非常相似,只需要使用deleteDocument()就可以了。
void Delete(string key, DirectoryInfo dir, StandardAnalyzer analyzer)
{
using (var directory = FSDirectory.Open(dir))
{
using (var indexWriter = new IndexWriter(directory, analyzer, false, IndexWriter.MaxFieldLength.LIMITED))
{
indexWriter.DeleteDocuments(new Term("Name", key));
indexWriter.Optimize();
indexWriter.Commit();
}
}
}
再来看看输出结果
可以发现 Score :0.7554128, Id :2, Name :橘子, Description :医生给娜美最珍贵的宝藏。这笔索引已经被移除罗!
可以发现笔者於更新或删除时都是输入单一字来做异动,除了表达可以对索引做复合更动外,
是因为更新与删除索引同样会使用到分词器(analyzer),
所输入的索引值非ID等数值时必须要配合分词器的分词能力才能取得所想异动的索引喔!
Boost是什麽呢?
Boost 分为 :
void CreateIndexWithBoost(List<Product> information, DirectoryInfo dir, StandardAnalyzer analyzer)
{
using (var directory = FSDirectory.Open(dir))
{
using (var indexWriter = new IndexWriter(directory, analyzer, true, IndexWriter.MaxFieldLength.LIMITED))
{
foreach (var index in information)
{
var document = new Document();
document.Add(new Field("Id", index.Id.ToString(), Field.Store.YES, Field.Index.NO));
document.Add(new Field("Name", index.Name, Field.Store.YES, Field.Index.ANALYZED));
document.Add(new Field("Description", index.Description, Field.Store.YES, Field.Index.ANALYZED));
document.GetField("Name").Boost = 1.5F;
document.GetField("Description").Boost = 0.5F;
indexWriter.AddDocument(document);
}
indexWriter.Optimize();
indexWriter.Commit();
}
}
}
并记得重新CreateIndex才能刷新栏位的权重值喔。
很明显的搜寻出来的Score分数变动了! 但是有没有发现明明Name栏位的Boost改成了1.5,苹果的数值却仍然只有一半呢?
这是因为我们的Search中所参照的栏位为Description,所以在计算Score的时候其实是完全没有参与的喔!
另外要记得,使用Index Time Boost的时候,欲给予铨重分配的栏位Field.Index不能使用NO_NORMS,不然这个栏位并不会纪录权重的资料。
再来我们试试看Query Time Boost
void SearchWithBoost(string searchValue, DirectoryInfo dir, StandardAnalyzer analyzer)
{
using (var directory = FSDirectory.Open(_dir))
{
using (var indexSearcher = new IndexSearcher(directory))
{
var query = new QueryParser(Lucene.Net.Util.Version.LUCENE_CURRENT, "Name", analyzer).Parse(searchValue);
var query2 = new QueryParser(Lucene.Net.Util.Version.LUCENE_CURRENT, "Description", analyzer).Parse(searchValue);
query.Boost = 2.0F;
query2.Boost = 0.5F;
BooleanQuery booleanQuery = new BooleanQuery();
booleanQuery.Add(query, Occur.SHOULD);
booleanQuery.Add(query2, Occur.SHOULD);
var hits = indexSearcher.Search(booleanQuery, 20);
if (!hits.ScoreDocs.Any())
{
Console.WriteLine("查无相关结果。");
return;
}
Document doc;
foreach (var hit in hits.ScoreDocs)
{
doc = indexSearcher.Doc(hit.Doc);
Console.WriteLine("Score :" + hit.Score + ", Id :" + doc.Get("Id") + ", Name :" + doc.Get("Name") + ", Description :" + doc.Get("Description"));
}
}
}
}
这次我们搜寻两个栏位"Name"与"Description",并使用 BooleanQuery来将其组合。
BooleanQuery中的 Occur有三种参数 : "MUST","MUST_NOT","SHOULD",功能与字面上的意思一样为"必须要有","必须没有"与"有无都包含"。
查询出来的分数就不一样罗!
以上就是这一次的分享,Lucene是一款容易入门但是要实际上战场却又十分复杂的功能,想要达成真正高效能的全文检索,在前期的文件规画配置与资料的权重配比都是一个巨大的挑战。未来会继续分享关於Lucene的其他有趣功能,还请继续期待呦!
另外也可以到我的GitHub下载范例来参考呦!
参考文件:
>>: 【C#】Behavioral Patterns Chain of Responsibility Mode
ES6:Promise Promise:代表一个即将成功或失败的非同步操作 会有这几状态: 搁置 (...
简介 今天要介绍的东西,是在编写程序的时候,可能需要具备的一个知识,但是好像不知道也不会影响那麽大(...
【前言】 终於到了验证的最後一步啦,感觉时间过得很快,一眨眼就到了这里,网站也变得非常完整。感谢大...
使用者意识 真为基础、善为核心、美为极致 承[Day24] Scrum失败经验谈 – 壁垒分明的职务...
在 Day2 提到什麽是用於生产的机械学习 ML in Production ,今天来谈用於生产的机...