• WEBUS2.0 In Action


    上一篇:WEBUS2.0 In Action - 搜索操作指南(3)

    6. 搜索多个索引

    为了提升性能, 我们可以从多个索引同时进行搜索, Webus.Search.MultiSearcher提供了相关功能:

    public MultiSearcher(ISearcher[] searchers) {...}

    我们将多个ISearcher对象传入MultiSearcher, 就可以像操作一个ISearcher对象那样进行搜索了. 

    IIndexer idx1 = new IndexManager();
    idx1.Open(@"c:index1");
    IIndexer idx2 = new IndexManager();
    idx2.Open(@"c:index2");
    ISearcher se1 = new IndexSearcher(idx1);
    ISearcher se2 = new IndexSearcher(idx2);
    ISearcher se = new MultiSearcher(new ISearcher[] { se1, se2 });
    var result = se.Search("Title="key"");

    由于MultiSearcher本身特性的限制, 如下方法和属性是不被支持的:

    public int MinDocId
    public int MaxDocId
    public void Open(string indexPath)
    public void Open(Webus.IO.IDirectory dir)
    public Document SelectDoc(int docId)
    public Document SelectDoc(int docId, string[] fieldnames)
    public List<Document> SelectDoc(int[] docIds)
    public List<Document> SelectDoc(int[] docIds, string[] fieldnames)

    值得注意的是, MultiSearcher会顺序调用所有的子搜索, 是顺序运行而非并发运行. 如果索引文件都在同一个物理磁盘上, 顺序运行的方式往往可以获得更好的性能. 不过如果我们有多块磁盘, 并且索引分别保存在不同的磁盘上, 那么我强烈推荐使用另外一种并发的搜索方式: Webus.Search.ParallelSearcher

    public ParallelSearcher(ISearcher[] searchers) {...}

    调用方式如下:

    IIndexer idx1 = new IndexManager();
    idx1.Open(@"c:index1"); //索引index1在C盘, C盘是物理磁盘1#
    IIndexer idx2 = new IndexManager();
    idx2.Open(@"d:index2"); //索引index2在D盘, D盘是物理磁盘2#
    ISearcher se1 = new IndexSearcher(idx1);
    ISearcher se2 = new IndexSearcher(idx2);
    ISearcher se = new ParallelSearcher(new ISearcher[] { se1, se2 });
    var result = se.Search("Title="key"");

    这个时候两块物理磁盘1#, 2#不会发生争用, 查询性能是能够得到明显提升的. 

    7. 缓存搜索结果

    内存存取速度是硬盘的100倍以上. 正因为这个原因, 磁盘索引永远不可能比内存索引快. 因此我们需要为搜索结果添加缓存来改善我们的应用程序性能. 为此WEBUS2.0 SDK提供了Webus.Searcher.CacheSearcher来实现搜索缓存的功能. 

    public CacheSearcher(IQueriable indexer) {...}
    public ICacher<string, Webus.Search.Hits> QueryCacher { get; set; }
    public ICacher<int, Webus.Documents.Document> DocCacher { get; set; }
    public ICacher<string, Webus.Documents.Field> FieldCacher { get; set; }

    在反复对10万数据级别的索引进行测试之后, 我们发现了如下三种缓存最能够提升性能:

    Query Cache
    对Search的结果进行缓存, 这些结果是最终结果. 这个缓存使用LRU算法进行调度, 同时由后台线程进行更新维护.

    Doc Cache
    通过分析索引中原始关键词的结果分布情况, 按照出现频率由高到低进行缓存. 这种缓存可以明显的改善数据加载性能, 其覆盖率与改善效果成正比. 这个缓存属于静态缓存, 数据一次性预加载到系统中.

    Field Cache
    通过预先加载可排序字段的值来提高排序性能. 这个缓存按照DocId由大到小进行加载. 也属于静态缓存, 数据一次性预加载到系统中. 值得注意的是, 这个缓存会尽量利用Doc Cache中已有的缓存数据来提高效率, 减少内存空间占用率.

    不论是QueryCache, DocCache还是FieldCahce, 都是ICacher类型, WEBUS中提供了两个ICahcer的实现:

    Webus.Search.Caches.LRUCacher - 近期最少使用缓存

    Webus.Search.Caches.LRUExpiryCacher - 近期最少使用过期缓存

    关于LRU算法, 网上有很多解释, 可以参照 http://baike.baidu.com/view/70151.htm

    至于LRUExpiry算法, 其实是在LRU的基础上增加过期策略, 并利用后台线程实时释放过期的缓存项目, 从而减小内存占用. 属于一种增强型算法. 

    使用CacheSearcher的示例代码如下:

    IIndexer idx = new IndexManager();
    idx.Open(@"c:index");
    CacheSearcher se = new CacheSearcher(idx);
    se.QueryCacher = new LRUCacher(1000); //MaxSize=1000
    se.DocCacher = new LRUCacher(1000);
    se.FieldCacher = new LRUCacher(1000);
    var result = se.Search("Title="key"");

    不论是LRUCacher还是LRUExpiryCacher, 我们可以通过指定缓存条目数(MaxSize)来限制内存占用. 需要注意的是这两种算法并非严格的遵循MaxSize的限制, 有时候也会可能超过这个限制, 但是马上会被后台维护线程发现并将需要淘汰的项目清除掉, 直至恢复到MaxSize之下.

    至此, WEBUS2.0搜索部分就全部介绍完了. 在搜索操作指南 - (1) 到 (4)中, 我们分别介绍了如下主题:

    • IQueriable内置的搜索功能
    • Query对象的使用
    • 对搜索结果进行评分, 排序和过滤
    • 搜索多个索引 (顺序, 并发)
    • 缓存搜索结果

    希望能够有所帮助. WEBUS2.2.3.9已经发布, 赶快集成到你的程序中去吧! 下载地址

    相关信息及WEBUS2.0 SDK下载:继续我的代码,分享我的快乐 - WEBUS2.0

    访问我们的站点: www.gdtsearch.com

  • 相关阅读:
    DLL注入之Appinit_Dlls
    VC下遍历文件夹中的所有文件的几种方法
    Windows下C语言的Socket编程例子(TCP和UDP)
    Windows进程间共享内存通信实例
    window下线程同步之(Mutex(互斥器) )
    如何安装win10和linux [ubuntu14]双系统
    Windows虚拟地址转物理地址(原理+源码实现,附简单小工具)
    Windows驱动中通过MDL实现用户态与核心态共享内存
    C# Label显示多行文本及换行(WinForm/WebForm)
    使用delegate实现简单的查询功能
  • 原文地址:https://www.cnblogs.com/iamzyf/p/3217007.html
Copyright © 2020-2023  润新知