您的位置:首页 > 其它

高级搜索 《第五篇》

2016-05-05 15:00 399 查看
高级搜索 《第五篇》

一、解析搜索请求

  搜索请求的概念是,用户输入关键词,然后程序去分析关键词,获取用户搜索的真实意图。

  Lucene提供了一套QueryParser类,用来解析搜索请求。这个类是可以使用的。

  1、QueryParser的基本使用

  QueryParser用来分析用户输入的关键词,将关键词转换成Query对象。其构造方法如下所示:

    QueryParser parser = new QueryParser(Lucene.Net.Util.Version.LUCENE_30, "title", new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_30));
Query q = parser.Parse("飞");
Console.WriteLine(q);   //title:飞


  这里,QueryParser解析成了:title:飞。

  2、使用QueryParser解析多个关键词

  如果将字符串“love mother”传递给搜索引擎,搜索引擎将如何去搜索?

  它可以执行如下操作:

搜索到所有含有"love"的记录以及所有含有"mother"的记录,然后将两部分记录加在一起,这是逻辑或的关系。

搜索到所有含有"love"的记录以及所有含有"mother"的记录,然后取它们的公共部分,这是逻辑与的关系。

  示例:

    QueryParser parser = new QueryParser(Lucene.Net.Util.Version.LUCENE_30, "title", new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_30));
Query q = parser.Parse("love mother");
Console.WriteLine(q);   //title:love title:mother


  从结果来看,Lucene把输入的关键词按照逻辑或的关系进行了处理。

  QueryParser解析的结果是: title:love title:mother 意思是,在“title”字段搜索“love”,在“title”字段搜索“mother”,两部分结果加到一起。我们可以修改这种逻辑,使其按照逻辑与的关系进行处理,也就是取出两个关键词的搜索结果的公共部分。

    QueryParser parser = new QueryParser(Lucene.Net.Util.Version.LUCENE_30, "title", new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_30));
parser.DefaultOperator = Lucene.Net.QueryParsers.QueryParser.Operator.AND;
Query q = parser.Parse("love mother");
Console.WriteLine(q);   //+title:love +title:mother


  Lucene引擎对关键词使用了逻辑与运算,解析结果为:

  +title:love +title:mother


  意思是,在“title”字段搜索“love”,在“title”字段搜索“mother”,两部分结果取公共部分。

  QueryParser类还有其他的一些用法,比如进行通配符识别和范围搜索识别等。但是,不建议使用QueryParser类来做搜索请求解析的工作,最好永远不要用这个类。对搜索请求的处理应该在搜索引擎程序前面一层的应用程序中去做,我们在这一层将用户输入的搜索关键词做好了解析之后,交给Query类去封装。

二、高级搜索

  高级搜索的内容包括:

多字段搜索;

多索引搜索;

多线程搜索;

  1、多字段搜索

  一个文档中含有“标题”,“正文”等字段,搜索一个关键词,不管它在标题中出现还是在正文中出现都算符合条件,这就是多字段搜索。

  1、利用BooleanQuery实现多字段搜索

  要实现多字段搜索很容易,利用前面学到的BooleanQuery就可以做到。首先设置两个TermQuery,然后在它们之间做逻辑运算即可。如下面的示例实现,title:张且body:打。

//建立索引
using (IndexWriter writer = new IndexWriter(ramdirectory, analyzer, maxFieldLength))
{
Document document1 = new Document();
document1.Add(new Field("title", "张飞牛人", Field.Store.YES, Field.Index.ANALYZED));
document1.Add(new Field("body", "张飞是一个牛人", Field.Store.YES, Field.Index.ANALYZED));
writer.AddDocument(document1);

Document document2 = new Document();
document2.Add(new Field("title", "张飞打架", Field.Store.YES, Field.Index.ANALYZED));
document2.Add(new Field("body", "张飞很能打", Field.Store.YES, Field.Index.ANALYZED));
writer.AddDocument(document2);
}

//查找
using (IndexSearcher searcher = new IndexSearcher(ramdirectory))
{
        Term t1 = new Term("title", "张");
TermQuery q1 = new TermQuery(t1);
Term t2 = new Term("body", "打");
TermQuery q2 = new TermQuery(t2);

BooleanQuery q = new BooleanQuery();
q.Add(q1, Occur.MUST);
q.Add(q2, Occur.MUST);

TopDocs docs = searcher.Search(q, null, 10);
for (int i = 0; i < docs.TotalHits; i++)
{
Document doc = searcher.Doc(docs.ScoreDocs[i].Doc); //输出 张飞打架
Console.WriteLine(doc.Get("title"));
}
}


  2、利用MultiFieldQueryParser实现多字段搜索

  除了通过使用BooleanQuery实现多字段搜索之外,Lucene还专门提供了一个MultiFieldQuery Parser类,用来实现多字段搜索。其实,只不过是个封装,用起来简单,内部还是用BooleanQuery实现的。

  其构造方法如下:

  MultiFieldQueryParser(Lucene.Net.Util.Version matchVersion, string[] fields, Analyzer analyzer)


  第一个参数是多个字段名称组成的数组,第二个参数是分析器对象实例。

string[] fields = { "title","body" };
MultiFieldQueryParser mp = new MultiFieldQueryParser(Lucene.Net.Util.Version.LUCENE_30, fields, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_30));
Query q = mp.Parse("打");


  以上是“或”关系。

  2、多索引搜索

  为了减少单个索引目录的大小,时常将索引放在许多目录中,这些索引的结构都是一致的。

  比如有一个城市的网站搜索引擎,随着时间的增长,我们可能会将索引的目录按照年份分成2003、2004、2005等。旧的索引目录被搜索的几率小,所以将其单独分出去,这样,可以减小新的索引目录,加快搜索速度。

  但是有些时候,必须实现多个索引的同时搜索,因为我们需要存放在这些索引中的信息。要实现多索引搜索,只需要对每个索引目录都用IndexSearcher搜索一遍,最后将搜索结果合并起来。

  Lucene中专门提供了MultiSearcher类来实现多索引搜索。使用MultiSearcher类实现多索引搜索的方法如下:

static void Main(string[] args)
{
Analyzer analyzer = new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_30);
IndexWriter.MaxFieldLength maxFieldLength = new IndexWriter.MaxFieldLength(10000);
DirectoryInfo dir = new DirectoryInfo(@"D:\1");
Lucene.Net.Store.Directory directory1 = new SimpleFSDirectory(dir);

DirectoryInfo dir2 = new DirectoryInfo(@"D:\2");
Lucene.Net.Store.Directory directory2 = new SimpleFSDirectory(dir2);

//建立索引
using (IndexWriter writer = new IndexWriter(directory1, analyzer, maxFieldLength))
{
Document document1 = new Document();
document1.Add(new Field("title", "张飞很能打", Field.Store.YES, Field.Index.ANALYZED));
writer.AddDocument(document1);
}

//建立索引
using (IndexWriter writer = new IndexWriter(directory2, analyzer, maxFieldLength))
{
Document document2 = new Document();
document2.Add(new Field("title", "关羽也很能打", Field.Store.YES, Field.Index.ANALYZED));
writer.AddDocument(document2);
}

        IndexSearcher searcher1 = new IndexSearcher(directory1);
IndexSearcher searcher2 = new IndexSearcher(directory2);
IndexSearcher[] searchers = { searcher1, searcher2 };

//查找
using (MultiSearcher MySearcher = new MultiSearcher(searchers))
{
Term t = new Term("title","打");
Query query = new TermQuery(t);
TopDocs docs = MySearcher.Search(query, null, 10);
for (int i = 0; i < docs.TotalHits; i++)
{
Document doc = MySearcher.Doc(docs.ScoreDocs[i].Doc); //输出 张飞打架 或关系
Console.WriteLine(doc.Get("title"));
}
}
Console.ReadKey();
}


  最后释放搜索器资源的时候,只需要关闭MultiSearcher的实例,在关闭它的时候,相应的几个IndexSearcher也都被关闭了。

  即调用了MySearch.Dispose();相当于调用了searcher1.Dispose();和searcher2.Dispose();

  3、多线程搜索

  MultiSearcher的实现机制是对IndexSearcher数组中的每个IndexSearcher对象执行搜索,得到的搜索结果之后合并到一起。在其中一个IndexSearcher执行搜索时,其他的IndexSearcher处于等待状态,因此,依然是一个目录一个目录地搜索,一个目录被搜索,其他目录在队列中等待。

  可以改良这种搜索方式,就是用多线程。同时检索多个索引目录。Lucene提供了ParallelMultiSearcher来实现多线程搜索。这个类是MultiSearcher的直接子类。其使用方法与MultiSearcher一致(一模一样)。

    IndexSearcher searcher1 = new IndexSearcher(directory1);
IndexSearcher searcher2 = new IndexSearcher(directory2);
IndexSearcher[] searchers = { searcher1, searcher2 };

//查找
using (ParallelMultiSearcher MySearcher = new ParallelMultiSearcher(searchers))


  使用方式与MultiSearcher一模一样,因此多余的代码不贴了。注意,这种方式在各个索引目录都比较大的情况下,效率提高会比较明显。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: