结合 DB 和 Lucene 搜索的最佳实践
Best Practice to Combine both DB and Lucene Search
我正在使用 .Net 开发高级搜索引擎,用户可以在其中基于多个字段构建查询:
- 标题
- 文档内容
- 开始日期,结束日期
- 从修改日期到修改日期
- 所有者
- 位置
- 其他元数据
我正在使用 lucene 来索引文档内容及其对应的 ID。但是,其他元数据驻留在 MS SQL DB 中(以避免扩大索引,并在元数据发生任何修改时不断更新索引)。
如何执行搜索?
当任何用户搜索某个词时:
- 根据用户在 SQL 数据库中查找选择的条件缩小搜索结果范围。
- Return lucene searcher web 服务的匹配 ID,它搜索在 Adv Search web 服务返回的文档 ID 中输入的关键字。
- 然后通过再次查看数据库获取文档 ID 的相关元数据(从 lucence 返回)。
正如您在这里注意到的那样,在 DB 中有一个查找,然后是 Lucene,最后是 DB 以获取要在 Grid 中显示的值。
问题:
如何克服这种情况?我想开始搜索 lucene,但如果索引的文档达到 200 万,这就有一个缺点。 (我认为首先使用数据库缩小结果对性能有很大影响)。
另一个问题是将 ID 传递给 lucene 搜索服务,传递数十万个 ID 的效率如何?替代解决方案是什么?
我欢迎任何想法,所以请分享您的想法。
您当前的解决方案在查询时会产生以下开销:
1) 通过 MS-SQL
缩小搜索 space
- 正在您的应用中生成查询
- 通过网络将其发送到 MS-SQL
- Parsing/Optimizing/Execution SQL 个查询
- [!!] I/O 返回 100,000 个 ID 的开销
2) 通过Lucene.NET
执行有界全文搜索
- [!!] generating/executing 大型 BooleanQuery 的 Lucene 内存开销在应用程序中包含 100,000 个 ID 子句(您需要首先覆盖默认限制1024 个条款甚至可以衡量这种效果)
- 标准 Lucene 全文搜索执行
- Return匹配 ID
3) 通过 MS-SQL
实现结果细节
- 搜索结果文档的快速、索引、基于 ID 的查找(只需要显示结果的第一页通常大约 10-25 条记录)
您可能做出的两个假设值得重新考虑
A) 索引所有元数据(日期、作者、位置等...)将不可接受地增加索引的大小。
首先尝试一下:这是最佳实践,通过让 Lucene 执行所有过滤,您将大大减少查询执行开销你除了文字搜索。
此外,索引的大小主要与每个字段的基数有关。例如,如果您只有 500 个唯一的所有者名称,那么只会存储这 500 个字符串,并且每个 lucene 文档将通过符号-table 查找(4 字节整数 * 2MM 文档 + 500字符串 = < 8MB 额外)。
B) MS-SQL 查询将是过滤非文本元数据的最快方式。
- 重新考虑: 使用适当的 Lucene 类型正确索引元数据后,与查询 MS-SQL 相比,查询 Lucene 不会产生任何额外开销。 (在某些情况下,Lucene 甚至可能更快。)
- 你的里程可能会有所不同,但根据我的经验,这种类型的过滤全文搜索在 2MM 文档的 Lucene 集合上执行时通常 运行 不到 100 毫秒。
总结最佳实践:
索引所有您要查询或筛选的数据。 (无需存储源数据,因为 MS-SQL 是您的记录系统)。
运行 针对 Lucene 的过滤查询(例如文本和日期范围、所有者、位置等...)
Return ID
使用返回的 ID 从 MS-SQL 实现文档。
我还建议探索迁移到独立搜索服务器(Solr 或 Elasticsearch)的原因有很多:
- 您不必担心搜索索引内存需求会蚕食应用程序内存需求。
- 您将利用复杂的过滤器缓存性能提升和基于 OS 的 I/O 优化。
- 您将能够从广泛 used/supported.
的主要基于配置的环境中轻松地迭代您的搜索解决方案
- 您将拥有适当的工具来 scale/tune/backup/restore 搜索而不影响您的应用程序。
我正在使用 .Net 开发高级搜索引擎,用户可以在其中基于多个字段构建查询:
- 标题
- 文档内容
- 开始日期,结束日期
- 从修改日期到修改日期
- 所有者
- 位置
- 其他元数据
我正在使用 lucene 来索引文档内容及其对应的 ID。但是,其他元数据驻留在 MS SQL DB 中(以避免扩大索引,并在元数据发生任何修改时不断更新索引)。
如何执行搜索?
当任何用户搜索某个词时:
- 根据用户在 SQL 数据库中查找选择的条件缩小搜索结果范围。
- Return lucene searcher web 服务的匹配 ID,它搜索在 Adv Search web 服务返回的文档 ID 中输入的关键字。
- 然后通过再次查看数据库获取文档 ID 的相关元数据(从 lucence 返回)。
正如您在这里注意到的那样,在 DB 中有一个查找,然后是 Lucene,最后是 DB 以获取要在 Grid 中显示的值。
问题:
如何克服这种情况?我想开始搜索 lucene,但如果索引的文档达到 200 万,这就有一个缺点。 (我认为首先使用数据库缩小结果对性能有很大影响)。
另一个问题是将 ID 传递给 lucene 搜索服务,传递数十万个 ID 的效率如何?替代解决方案是什么?
我欢迎任何想法,所以请分享您的想法。
您当前的解决方案在查询时会产生以下开销:
1) 通过 MS-SQL
缩小搜索 space- 正在您的应用中生成查询
- 通过网络将其发送到 MS-SQL
- Parsing/Optimizing/Execution SQL 个查询
- [!!] I/O 返回 100,000 个 ID 的开销
2) 通过Lucene.NET
执行有界全文搜索- [!!] generating/executing 大型 BooleanQuery 的 Lucene 内存开销在应用程序中包含 100,000 个 ID 子句(您需要首先覆盖默认限制1024 个条款甚至可以衡量这种效果)
- 标准 Lucene 全文搜索执行
- Return匹配 ID
3) 通过 MS-SQL
实现结果细节- 搜索结果文档的快速、索引、基于 ID 的查找(只需要显示结果的第一页通常大约 10-25 条记录)
您可能做出的两个假设值得重新考虑
A) 索引所有元数据(日期、作者、位置等...)将不可接受地增加索引的大小。
首先尝试一下:这是最佳实践,通过让 Lucene 执行所有过滤,您将大大减少查询执行开销你除了文字搜索。
此外,索引的大小主要与每个字段的基数有关。例如,如果您只有 500 个唯一的所有者名称,那么只会存储这 500 个字符串,并且每个 lucene 文档将通过符号-table 查找(4 字节整数 * 2MM 文档 + 500字符串 = < 8MB 额外)。
B) MS-SQL 查询将是过滤非文本元数据的最快方式。
- 重新考虑: 使用适当的 Lucene 类型正确索引元数据后,与查询 MS-SQL 相比,查询 Lucene 不会产生任何额外开销。 (在某些情况下,Lucene 甚至可能更快。)
- 你的里程可能会有所不同,但根据我的经验,这种类型的过滤全文搜索在 2MM 文档的 Lucene 集合上执行时通常 运行 不到 100 毫秒。
总结最佳实践:
索引所有您要查询或筛选的数据。 (无需存储源数据,因为 MS-SQL 是您的记录系统)。
运行 针对 Lucene 的过滤查询(例如文本和日期范围、所有者、位置等...)
Return ID
使用返回的 ID 从 MS-SQL 实现文档。
我还建议探索迁移到独立搜索服务器(Solr 或 Elasticsearch)的原因有很多:
- 您不必担心搜索索引内存需求会蚕食应用程序内存需求。
- 您将利用复杂的过滤器缓存性能提升和基于 OS 的 I/O 优化。
- 您将能够从广泛 used/supported. 的主要基于配置的环境中轻松地迭代您的搜索解决方案
- 您将拥有适当的工具来 scale/tune/backup/restore 搜索而不影响您的应用程序。