Lucene.Net操作上的一些技巧

以下例子采用 Lucene.NET 1.9 版本,可取去 Lucene.Net 下载。

1. 基本应用

using System;

using System.
Collections.Generic;

using System.Text;

using Lucene.Net;

using Lucene.Net.Analysis;

using Lucene.Net.Analysis.Standard;

using Lucene.Net.Documents;

using Lucene.Net.Index;

using Lucene.Net.QueryParsers;

using Lucene.Net.Search;

using Lucene.Net.Store;

using Lucene.Net.Util;

namespace
Console
Application1.Lucene

{

public class LuceneTest

{

private const string FieldName = "name";

private const string FieldValue = "value";

private
Directory directory = new RAMDirectory();

private Analyzer analyzer = new StandardAnalyzer();

public LuceneTest()

{

}

private void Index()

{

IndexWriter writer = new IndexWriter(directory, analyzer, true);

writer.maxFieldLength = 1000;

for (int i = 1; i <= 100; i++)

{

Document document = new Document();

document.Add(new Field(FieldName, "name" + i, Field.Store.YES, Field.Index.UN_TOKENIZED));

document.Add(new Field(FieldValue, "Hello, World!", Field.Store.YES, Field.Index.TOKENIZED));

writer.AddDocument(document);

}

writer.Optimize();

writer.Close();

}

private void Search()

{

Query query = QueryParser.Parse("name*", FieldName, analyzer);

IndexSearcher searcher = new IndexSearcher(directory);

Hits hits = searcher.Search(query);

Console.WriteLine("符合条件记录:{0}; 索引库记录总数:{1}", hits.Length(), searcher.Reader.NumDocs());

for (int i = 0; i < hits.Length(); i++)

{

int docId = hits.Id(i);

string name = hits.Doc(i).Get(FieldName);

string value = hits.Doc(i).Get(FieldValue);

float score = hits.Score(i);

Console.WriteLine("{0}: DocId:{1}; Name:{2}; Value:{3}; Score:{4}",

i + 1, docId, name, value, score);

}

searcher.Close();

}

}

}

除了 RAMDirectory,还可以使用 FSDirectory。(注意 FSDirectory.GetDirectory 的 create 参数,为 true 时将删除已有索引库文件,可以通过 IndexReader.IndexExists() 方法判断。)

从指定目录打开已有索引库。

private Directory directory = FSDirectory.GetDirectory("c:\index", false);

将索引库载入内存,以提高搜索速度。

private Directory directory = new RAMDirectory(FSDirectory.GetDirectory(@"c:\index", false));
//或
//private Directory directory = new RAMDirectory(c:\index");

2. 多字段搜索

使用 MultiFieldQueryParser 可以指定多个搜索字段。

Query query = MultiFieldQueryParser.Parse("name*", new string[] { FieldName, FieldValue }, analyzer);

IndexReader reader = IndexReader.Open(directory);

IndexSearcher searcher = new IndexSearcher(reader);

Hits hits = searcher.Search(query);

3. 多条件搜索
除了使用 QueryParser.Parse 分解复杂的搜索语法外,还可以通过组合多个 Query 来达到目的。

Query query1 = new TermQuery(new Term(FieldValue, "name1")); // 词语搜索

Query query2 = new WildcardQuery(new Term(FieldName, "name*")); // 通配符

//Query query3 = new PrefixQuery(new Term(FieldName, "name1")); // 字段搜索 Field:Keyword,自动在结尾添加 *

//Query query4 = new RangeQuery(new Term(FieldNumber, NumberTools.LongToString(11L)), new Term(FieldNumber, NumberTools.LongToString(13L)), true); // 范围搜索

//Query query5 = new FilteredQuery(query, filter); // 带过滤条件的搜索

BooleanQuery query = new BooleanQuery();

query.Add(query1, BooleanClause.Occur.MUST);

query.Add(query2, BooleanClause.Occur.MUST);

IndexSearcher searcher = new IndexSearcher(reader);

Hits hits = searcher.Search(query);

4. 设置权重

可以给 Document 和 Field 增加权重(Boost),使其在搜索结果排名更加靠前。缺省情况下,搜索结果以 Document.Score 作为排序依据,该数值越大排名越靠前。Boost 缺省值为 1。

Score = Score * Boost

通过上面的公式,我们就可以设置不同的权重来影响排名。

如下面的例子中根据 VIP 级别设定不同的权重。

Document document = new Document();

switch (vip)

{

case VIP.Gold: document.SetBoost(2F); break;

case VIP.Argentine: document.SetBoost(1.5F); break;

}

只要 Boost 足够大,那么就可以让某个命中结果永远排第一位,这就是百度等网站的"收费排名"业务。明显有失公平,鄙视一把。

5. 排序

通过 SortField 的构造参数,我们可以设置排序字段,排序条件,以及倒排。

Sort sort = new Sort(new SortField(FieldName, SortField.DOC, false));

IndexSearcher searcher = new IndexSearcher(reader);

Hits hits = searcher.Search(query, sort);

排序对搜索速度影响还是很大的,尽可能不要使用多个排序条件。

6. 过滤

使用 Filter 对搜索结果进行过滤,可以获得更小范围内更精确的结果。
举个例子,我们搜索上架时间在 2005-10-1 到 2005-10-30 之间的商品。
对于日期时间,我们需要转换一下才能添加到索引库,同时还必须是索引字段。

//index

document.Add(FieldDate, DateField.DateToString(date), Field.Store.YES, Field.Index.UN_TOKENIZED);

//...

// search

Filter filter = new DateFilter(FieldDate, DateTime.Parse("2005-10-1"), DateTime.Parse("2005-10-30"));

Hits hits = searcher.Search(query, filter);

除了日期时间,还可以使用整数。比如搜索价格在 100 ~ 200 之间的商品。
Lucene.Net NumberTools 对于数字进行了补位处理,如果需要使用浮点数可以自己参考源码进行。
// index
document.Add(new Field(FieldNumber, NumberTools.LongToString((long)price), Field.Store.YES, Field.Index.UN_TOKENIZED));

//...

// search
Filter filter = new RangeFilter(FieldNumber, NumberTools.LongToString(100L), NumberTools.LongToString(200L), true, true);
Hits hits = searcher.Search(query, filter);

使用 Query 作为过滤条件。
QueryFilter filter = new QueryFilter(QueryParser.Parse("name2", FieldValue, analyzer));

我们还可以使用 FilteredQuery 进行多条件过滤。

Filter filter = new DateFilter(FieldDate, DateTime.Parse("2005-10-10"), DateTime.Parse("2005-10-15"));
Filter filter2 = new RangeFilter(FieldNumber, NumberTools.LongToString(11L), NumberTools.LongToString(13L), true, true);

Query query = QueryParser.Parse("name*", FieldName, analyzer);
query = new FilteredQuery(query, filter);
query = new FilteredQuery(query, filter2);

IndexSearcher searcher = new IndexSearcher(reader);
Hits hits = searcher.Search(query);
7. 分布搜索

我们可以使用 MultiReader 或 MultiSearcher 搜索多个索引库。

MultiReader reader = new MultiReader(new IndexReader[] { IndexReader.Open(@"c:\index"), IndexReader.Open(@"\\server\index") });
IndexSearcher searcher = new IndexSearcher(reader);
Hits hits = searcher.Search(query);

IndexSearcher searcher1 = new IndexSearcher(reader1);
IndexSearcher searcher2 = new IndexSearcher(reader2);
MultiSearcher searcher = new MultiSearcher(new Searchable[] { searcher1, searcher2 });
Hits hits = searcher.Search(query);

还可以使用 ParallelMultiSearcher 进行多线程并行搜索。

8. 合并索引库

将 directory1 合并到 directory2 中。

Directory directory1 = FSDirectory.GetDirectory("index1", false);

Directory directory2 = FSDirectory.GetDirectory("index2", false);

IndexWriter writer = new IndexWriter(directory2, analyzer, false);

writer.AddIndexes(new Directory[] { directory });

Console.WriteLine(writer.DocCount());

writer.Close();

9. 显示搜索语法字符串

我们组合了很多种搜索条件,或许想看看与其对等的搜索语法串是什么样的。
BooleanQuery query = new BooleanQuery();
query.Add(query1, true, false);
query.Add(query2, true, false);
//...

Console.WriteLine("Syntax: {0}", query.ToString());

输出:
Syntax: +(name:name* value:name*) +number:[0000000000000000b TO 0000000000000000d]

呵呵,就这么简单。

10. 操作索引库

删除 (软删除,仅添加了删除标记。调用 IndexWriter.Optimize() 后真正删除。)
IndexReader reader = IndexReader.Open(directory);

// 删除指定序号(DocId)的 Document。
reader.Delete(123);

// 删除包含指定 Term 的 Document。
reader.Delete(new Term(FieldValue, "Hello"));

// 恢复软删除。
reader.UndeleteAll();

reader.Close();

增量更新 (只需将 create 参数设为 false,即可往现有索引库添加新数据。)

Directory directory = FSDirectory.GetDirectory("index", false);

IndexWriter writer = new IndexWriter(directory, analyzer, false);

writer.AddDocument(doc1);

writer.AddDocument(doc2);

writer.Optimize();

writer.Close();

11. 优化

批量向 FSDirectory 增加索引时,增大合并因子(mergeFactor )和最小文档合并数(minMergeDocs)有助于提高性能,减少索引时间。

IndexWriter writer = new IndexWriter(directory, analyzer, true);

writer.maxFieldLength = 1000; // 字段最大长度

writer.mergeFactor = 1000;

writer.minMergeDocs = 1000;

for (int i = 0; i < 10000; i++)

{

// Add Documentes...

}

writer.Optimize();

writer.Close();

//...

时间: 2024-09-22 10:53:43

Lucene.Net操作上的一些技巧的相关文章

艾伟_转载:Lucene.Net操作上的一些技巧

以下例子采用 Lucene.NET 1.9 版本,可取去 Lucene.Net 下载. 1. 基本应用 using System;using System.Collections.Generic;using System.Text;using Lucene.Net;using Lucene.Net.Analysis;using Lucene.Net.Analysis.Standard;using Lucene.Net.Documents;using Lucene.Net.Index;using

Webbrowser控件史上最强技巧全集

原文:Webbrowser控件史上最强技巧全集 Webbrowser控件史上最强技巧全集 VB调用webbrowser技巧集 1.获得浏览器信息: Private Sub Command1_Click() WebBrowser1.Navigate "http://www.applevb.com" End Sub Private Sub Command2_Click() Dim oWindow Dim oNav Set oWindow = WebBrowser1.Document.par

PHP链表操作简单示例_php技巧

本文实例讲述了PHP链表操作.分享给大家供大家参考,具体如下: 在php中运行数据结构,基本都是用数组模拟的,只是用一直思想而已. 今天遇到的这个问题是,两个链表进行合并. 链表合并效果图 问题描述:A链表是模版链表,B链表的长度不确定,A,B二个链表结合后形成C链表. 说一下编程思想:A链表是模版链表所以在运算完成了,长度了唯一不变的.而B链表的长度是不确定的.所以可以先对B链表进行判断,分了三步: B链表是不是为空 B链表是不是比A链表短或者相等 B链表是不是比A链表长 编程就是要列出尽可能

cad2010三维操作-求助CAD2010三维操作上面的怎么画

问题描述 求助CAD2010三维操作上面的怎么画 CAD2010上面的怎么画

由于ACCESS和SQL Server数据库是经常使用的两种数据库, 而且操作上很相似,决定将代码写在一起,但在操作上出了问题

问题描述 问题:由于ACCESS和SQLServer数据库是经常使用的两种数据库,而且操作上很相似,决定将代码写在一起,用一个数据库类型选择来做判断,代码如下//数据库类型选择if(DatabaseType=="ACCESS"){OleDbDataReadermyReader=GetMyOleDbDataReader(mySql);}else{SqlDataReadermyReader=GetMyReader(mySql);}if(myReader.Read()){//执行语句}错误提

PHP的PDO操作简单示例_php技巧

本文实例讲述了PHP的简单PDO操作.分享给大家供大家参考,具体如下: 网上关于PDO的资料很多.这里就不累赘了. 这里我将PDO所有操作封装到一个类里方便操作. 类代码如下: class DB { //pdo对象 public $con = NULL; function DB() { $this->con = new PDO("mysql:host=127.0.0.1;dbname=dbtest", "root", "xxx", arra

PHP目录操作实例总结_php技巧

本文实例总结了PHP目录操作方法.分享给大家供大家参考,具体如下: 目录操作 新建目录:mkdir(路径,权限,递归创建) 删除目录:rmdir() 移动(改名):rename() 获取目录内容: //打开目录 目录句柄 = opendir() //读取目录 文件名 = readdir(目录句柄) 依次读取文件名,同时向下移动文件句柄指针,读取不到则返回false //关闭目录 closedir() 递归读取目录内容: <?php showDir('../../file'); function

铝价破位后将陷单边下跌 操作上逢高沽空为主

在国际国内铝市场供需关系维持偏空背景下,国内对铝出口进行调控,导致铝价内外盘持续单边下跌.LME期铝周一大幅收跌35美元至2395美元,不但跌破2400美元整数位,还创下3月31日低点2460美元以来五个多月的新低.从技术上看,LME期铝短线将寻求2200美元一线支撑作用,操作上宜以逢高沽空为主. 在伦铝破位的情况下,昨天的沪铝也联动走弱,全天总成交17066手,持仓量净减1028手至118274手.其中,主力合约AL712收跌40元至19250元,空方主力的沉重打压,引发多头投机资金主动回吐,

ASP常用数据库连接及操作的方法和技巧

技巧|数据|数据库|数据库连接 1.ASP连接Access数据库 <%dim conn,mdbfile mdbfile=server.mappath("数据库名称.mdb") set conn=server.createobject("adodb.connection") conn.open "driver={microsoft access driver (*.mdb)};uid=admin;pwd=数据库密码;dbq="&mdb