lucene.net学习六——多Field多索引文件的查询

时间:2021-03-23 03:05:29

在实际的需求中,我们需要输入一个关键语句,希望能搜索到标题中含有此关键词或者内容中也还有此关键语句的文章,这就是一个多Field查询的问题

当然多Field之间的关系可能为“与”也有可能为“或”。一般情况下,都在同一个目录索引下搜索,但是如果索引被分成很多文件,存在不同的地方,因此又会有一个多索引文件搜索的问题。下面通过代码演示:

首先编写建索引的代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.IO;
using Lucene.Net;
using Lucene.Net.Util;
using Lucene.Net.Store;
using Lucene.Net.Analysis;
using Lucene.Net.Index;
using Lucene.Net.Documents;

namespace TestIndexWriter
{
class Program
{
static void Main(string[] args)
{
//需要被索引的目录
FileInfo fi = new FileInfo(@"F:\doc");
//索引存放的路径
Lucene.Net.Store.Directory indexdir = FSDirectory.Open(new DirectoryInfo(@"F:\luceneindex1"));
//建立一个处理文本的分析器
Analyzer analyzer = new Lucene.Net.Analysis.Standard.StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29);
//创建索引写入器
IndexWriter writer = new IndexWriter(indexdir, analyzer, true, new IndexWriter.MaxFieldLength(10000));
//递归遍历指定目录下的所有的文件,并建立索引
IndexDocs(writer, fi);
Console.WriteLine("索引存放的目录为:F:\\luceneindex1");
writer.Close();
}

//遍历指定目录下的所有文件进行索引
private static void IndexDocs(IndexWriter writer, FileInfo file)
{
//判断指定的目录是否存在,注意不是文件的路径,C#中目录与文件的区别
//Directory.Exists()是判断指定的目录是否存在,而File.Exists()则是判断指定的文件是否存在
if (System.IO.Directory.Exists(file.FullName))
{
//获取指定目录中的所有文件和子目录
System.String[] files = System.IO.Directory.GetFileSystemEntries(file.FullName);
if (files != null)
{
for (int i = 0; i < files.Length; i++)
{
IndexDocs(writer, new System.IO.FileInfo(files[i]));//递归调用
}
}
}
//不是目录了,是文件,就开始加入索引
else
{
System.Console.WriteLine("开始索引文件: " + file.FullName);
try
{
Document d = new Document();
//对路径进行存储、索引但不分词
d.Add(new Field("path",file.FullName, Field.Store.YES, Field.Index.NOT_ANALYZED));
d.Add(new Field("contents", new StreamReader(file.FullName, System.Text.Encoding.Default)));
writer.AddDocument(d);
}
catch (System.IO.FileNotFoundException fnfe)
{
Console.WriteLine(fnfe.Message);
}
}
}
}
}

上面代码的意思是遍历目录F:\doc下的所有文件,并建立索引,建好后的索引存放在F:\luceneindex1下面。运行结果如下:

lucene.net学习六——多Field多索引文件的查询

修改上面代码中的//需要被索引的目录
            FileInfo fi = new FileInfo(@"F:\doc1");
            //索引存放的路径
            Lucene.Net.Store.Directory indexdir = FSDirectory.Open(new DirectoryInfo(@"F:\luceneindex2"));

表示遍历目录F:\doc1下的所有文件,并建立索引,索引存放在F:\luceneindex2下,运行结果如下:

 

lucene.net学习六——多Field多索引文件的查询

到此相当于生成了两个不同路径下的索引文件。

下面开始编写所Field多索引文件搜索的代码。

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.IO;
using Lucene.Net;
using Lucene.Net.Search;
using Lucene.Net.Store;
using Lucene.Net.Analysis.Standard;
using Lucene.Net.Index;
using Lucene.Net.Documents;
using Lucene.Net.QueryParsers;

namespace MultiFieldMultiSearch
{
class Program
{
static void Main(string[] args)
{
//索引存放的路径1
Lucene.Net.Store.Directory indexdir1 = FSDirectory.Open(new DirectoryInfo(@"F:\luceneindex1"));
//初始化一个读索引器1
IndexSearcher IS1 = new IndexSearcher(indexdir1, true);

//索引存放的路径2
Lucene.Net.Store.Directory indexdir2 = FSDirectory.Open(new DirectoryInfo(@"F:\luceneindex2"));
//初始化一个读索引器2
IndexSearcher IS2 = new IndexSearcher(indexdir2, true);
//查询器数组
IndexSearcher[] searchers={IS1,IS2};
//构造一个多索引的查询器
MultiSearcher search = new MultiSearcher(searchers);

//2个需要查询的域名称
string[] fields={"filename","contents"};
//将每个域Field所查询的结果设为“或”的关系,也就是取并集
BooleanClause.Occur[] clauses={BooleanClause.Occur.SHOULD,BooleanClause.Occur.SHOULD};
//构造一个多Field查询
Query query = MultiFieldQueryParser.Parse(Lucene.Net.Util.Version.LUCENE_29, "郭靖", fields, clauses,
new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29));
Console.WriteLine(string.Format("查询条件为:{0}", query.ToString()));
Hits hits = search.Search(query);
for (int i = 0; i < hits.Length(); i++)
{
//更具文档的编号得到文档对象
Document doc = hits.Doc(i);
//根据给定的Filed名,得到对应的值
Console.WriteLine(doc.Get("path"));
//输出此文档的得分在结果集中
Console.WriteLine(hits.Score(i));
}
search.Close();
}
}
}

运行输出结果为:

lucene.net学习六——多Field多索引文件的查询

 在代码里面输入"郭靖"作为查询词,根据lucene.net的标准分词方法,将“郭靖”分解为“郭”、“靖”这两个词,建索引的时候也是这样分解的,所以一定要保证建索引用的分词器与查询时用的分词器保持一致。

上面的查询条件的意思就是搜索包含郭或靖的文件名的文件,搜索包含郭或靖的内容的文件,两者的结果取并集

结果中还返回了每一个文件Document的打分