LevelSearch 0.1.1

LevelSearch 0.1.1

测试已测试
Lang语言 Obj-CObjective C
许可证 MIT
发布上次发布2014年5月

未知的拥有者维护。



  • 作者
  • John Tumminaro

简介

尽管苹果有一个现成的全文搜索解决方案,形式为搜索套件,但它有几个主要的缺点。

  • 它仅限于Mac OS X。
  • 它是一个C语言编写的API,位于核心服务框架中,并且没有等效的Objective-C API。
  • 它未与Core Data集成,虽然可以与Core Data一起启动并运行,但并不是一个非常容易替换的解决方案。

目前有几个解决此问题的方案,但它们并不完美

  • 您可以使用NSPredicate并结合CONTAINS或BEGINSWITH执行查询。这对于快速搜索来说真的很不实用,尤其是如果您想进行对大小写和变音符号敏感的搜索。
  • RestKit有一个与Core Data一起工作的搜索解决方案,将搜索索引视为与索引模型的同一Core Data存储中的对象。这很方便,但它与RestKit的绑定比较紧密,我发现使用sqlite在索引或搜索方面的性能并不是很好。考虑到Core Data和sqlite并非特别针对此用例进行优化,这是可以理解的限制。
  • 您可以使用此处描述的sqlite的FTS3/FTS4扩展。虽然这可行,但需要与您的应用程序捆绑自定义构建的sqlite3(由于它使用较旧版本,这带来了一些配置挑战,并与Core Data一起使用)以及仍然需要手动处理Core Data保存通知和执行自定义索引。

这就是LevelSearch发挥作用的地方。它设计得易于集成,同时保持最低的影响(没有objc/runtime或相关对象),并提供了可以满足需要如自动完成这样的低延迟用例的全文搜索的性能。

架构

正如其名所示,LevelSearch是基于Google开发的LevelDB键/值数据库构建的,该数据库采用BSD许可发布。它是一个高性能键/值存储,类似于Redis,但它针对的是嵌入式客户端用途,例如Chrome浏览器,这使得它在这种用例中非常棒。有关更多信息,您可以先看看Google的文档。

这表示 LevelSearch 使用每个索引的 LevelDB 实例,其基于文件支持自行持久化。LevelSearch 支持单个共享便利索引或多个命名索引——如何最有效地利用它完全取决于您的用例。

尽管 LevelSearch 在技术上使用了一些功能,但它真的非常容易使用,因为它使用 Core Data 保存通知来管理所有的索引更改。一旦它开始监视某个 NSManagedObjectContext,索引将愉快地继续索引和更新索引,一旦检测到 Core Data 的更改。这种紧密耦合使得 Level Search 非常流线型,实现相当精简,大约 500 LOC(不包括 LevelDB 库和 Objective-C 封装)。

它也非常快,更多相关信息请见下面的基准。

安装

之后,只需导入共享头文件即可。

#import <LevelSearch/LevelSearch.h> 

使用

使用 LevelSearch 非常简单,您只需配置索引,其余的都由它来处理。

配置索引

如果您只需要单个索引,则共享索引效果很好。要在 Core Data 配置完成后设置它,请按照以下步骤进行:

 [[LSIndex sharedIndex] addIndexingToEntity:[NSEntityDescription entityForName:@"ExampleEntity" inManagedObjectContext:ExampleContext] forAttributes:@[@"attribute1", @"attribute2"]];
 [[LSIndex sharedIndex] startWatchingManagedObjectContext:ExampleContext];

这确实非常简单。尽管如此,需要注意的是,由于 LevelSearch 不使用任何运行时技巧,它无法向您的托管对象添加任何类型的键。这在大多数情况下是个好事,但鉴于 Core Data 提供的唯一真实主键是 NSManagedObjectID,因此需要在将对象保存到持久存储之前将其索引(因为对象 ID 是临时的并且可以更改,直到对象被保存)。

这意味着您应该监视直接连接到 NSPersistentStoreCoordinator 的 NSManagedObjectContext,而不是子上下文。如果您只使用一个上下文,例如苹果的默认 Core Data 代码,则没问题;如果您使用 MagicalRecord(或类似使用主线程上下文和父保存上下文的堆栈)则想要这样做:

 [[LSIndex sharedIndex] startWatchingManagedObjectContext:[NSManagedObjectContext MR_rootSavingContext]];

配置索引后,您真的不需要做任何事情,索引将注册 Core Data 保存通知并通过 Core Data 自动索引对象。如果您想要更精细地控制索引何时发生,则可以使用 LSIndexDelegate 协议或通知。这两个都提供完整文档。

查询索引

有两种查询方法:同步和异步查询方法。对于大多数人来说,异步方法被广泛采用,因为您不希望在用户输入搜索词时主线程有延迟。同步方法对于测试有帮助,如果您想要拥有自己的搜索队列,则可以自行实现异步搜索,但请做好善事,请不要从主线程调用这些方法。

在其他方面,同步和异步查询之间的查询接口是相同的,一个简单的查询如下:

        [[LSIndex sharedIndex] queryInBackgroundWithString:@"example query"
                                           withResults:^(NSSet *results) {
                                               // Put your completion code here...
                                           }];

查询返回的结果是 Core Data 对象的 NSSet,您甚至不需要执行自己的 NSFetchRequest...查询已经为您处理了一切。您可能想要使用 NSSortDescriptor 将结果排序成一个 NSArray,但这非常直观。

示例项目

要运行示例项目;首先克隆仓库,然后从根目录运行pod install。有两个示例应用程序:一个用于展示如何集成框架,另一个用于性能和集成测试。

性能测试

要求

作者

John Tumminaro, [email protected]

许可证

LevelSearch遵循MIT许可。更多信息请参阅LICENSE文件。