lucene 高级搜索

来源:互联网 发布:淘宝 非常小非常小的店 编辑:程序博客网 时间:2024/05/20 05:29

出处:http://www.cnblogs.com/kissdodog/p/3640349.html  感谢您的文章


一、解析搜索请求

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

  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”传递给搜索引擎,搜索引擎将如何去搜索?

  它可以执行如下操作:

  1. 搜索到所有含有"love"的记录以及所有含有"mother"的记录,然后将两部分记录加在一起,这是逻辑或的关系。
  2. 搜索到所有含有"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一模一样,因此多余的代码不贴了。注意,这种方式在各个索引目录都比较大的情况下,效率提高会比较明显。

0 0
原创粉丝点击