zoukankan
html css js c++ java
[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
Lucene.Net.QueryParsers;
using
Lucene.Net.Search;
using
Lucene.Net.Store;
using
Lucene.Net.Util;
namespace
ConsoleApplication1.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();
相关参数说明
转自《深入 Lucene 索引机制》
利用 Lucene,在创建索引的工程中你可以充分利用机器的硬件资源来提高索引的效率。当你需要索引大量的文件时,你会注意到索引过程的瓶颈是在往磁盘上写索引文件的过程中。为了解决这个问题, Lucene 在内存中持有一块缓冲区。但我们如何控制 Lucene 的缓冲区呢?幸运的是,Lucene 的类 IndexWriter 提供了三个参数用来调整缓冲区的大小以及往磁盘上写索引文件的频率。
1
.合并因子 (mergeFactor)
这个参数决定了在 Lucene 的一个索引块中可以存放多少文档以及把磁盘上的索引块合并成一个大的索引块的频率。比如,如果合并因子的值是
10
,那么当内存中的文档数达到
10
的时候所有的文档都必须写到磁盘上的一个新的索引块中。并且,如果磁盘上的索引块的隔数达到
10
的话,这
10
个索引块会被合并成一个新的索引块。这个参数的默认值是
10
,如果需要索引的文档数非常多的话这个值将是非常不合适的。对批处理的索引来讲,为这个参数赋一个比较大的值会得到比较好的索引效果。
2
.最小合并文档数 (minMergeDocs)
这个参数也会影响索引的性能。它决定了内存中的文档数至少达到多少才能将它们写回磁盘。这个参数的默认值是10,如果你有足够的内存,那么将这个值尽量设的比较大一些将会显著的提高索引性能。
3
.最大合并文档数 (maxMergeDocs)
这个参数决定了一个索引块中的最大的文档数。它的默认值是 Integer.MAX_VALUE,将这个参数设置为比较大的值可以提高索引效率和检索速度,由于该参数的默认值是整型的最大值,所以我们一般不需要改动这个参数。
-------------------
迷糊中的分割线
-----------------------------
Lucene 相关资源:
1
. Lucene 官方网站
2
. Apache Lucene
3
. Lucene FAQ
4
. Lucene.Net
5
. Lucene API (Java)
6
. DotLucene
7
. Luke
-
Lucene Index Toolbox
8
. Nutch
9
. LUCENE.COM.CN 中国
10
. Compass
11
. 实战 Lucene,第
1
部分: 初识 Lucene
12
. 深入 Lucene 索引机制
原地址:http:
//
www.rainsts.net/article.asp?id=313
查看全文
相关阅读:
jmeter如何连接数据库
jmeter基础之录制篇
php解压缩
composer基本使用
react组件之间的参数传递
解决VMware Workstation 不可恢复错误: (vcpu-0)
虚拟机vmware11装Mac ox 10.8 解决windows8.1下unlocker202 vmxsmc.exe已停止工作的问题
Photoshop学习:打开PS之前需要...
汇编语言之启航
Markdown语法介绍
原文地址:https://www.cnblogs.com/kokoliu/p/965733.html
最新文章
Java面试之前复习总结(一)
【设计模式】之单例模式
Java集合总结
坚持下来~
java之反射
SSH框架整合
原码、反码、补码
VS2017搭建驱动开发环境WDK
WireShark捕获HTTPS
博客模板更新
热门文章
挖洞手记——软媒魔方可信任程序执行漏洞
风雨集
evil program
Linux常用命令及搭建测试环境
接口测试必备技能之入门到上手
玩玩自动化测试之selenium篇
monkey测试
adb常用命令
jmeter关联三种常用方法
jmeter的脚本增强之参数化
Copyright © 2011-2022 走看看