zoukankan      html  css  js  c++  java
  • 艾伟_转载: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();
    //...
  • 相关阅读:
    HTML&&CSS
    web概述&HTML快速入门
    JDBC连接池&JDBCTemplate
    基于Breast Cancer dataset的决策树分类及可视化
    三维数组按行优先存储求某位置的地址
    2019年复旦计算机专硕考研经验总结
    1013 Battle Over Cities (25 分)
    1009 Product of Polynomials (25 分)
    1004 Counting Leaves (30 分)
    1090 危险品装箱 (25 分)
  • 原文地址:https://www.cnblogs.com/waw/p/2157036.html
Copyright © 2011-2022 走看看