我试图弄清楚如何根据关键字匹配过滤一大堆文档。
我的SQL数据库中有ID +和(几个)文本字段的20 +百万个条目,我希望得到文本与一组关键字匹配的所有ID。这包括更复杂的表达式,如:
(term1 NEAR term2 NEAR term3) AND NOT "A phrase" AND @fieldXYZ "wildcards%aswell*"
不需要以任何方式对结果进行评分,排序或排名。
据我了解Lucene / Solr的强大功能,Sphinx和ElasticSearch将以极快的速度回馈TOP文档,但它们并非真正打算回赠所有文档。
我知道可以使用Lucene中的自定义收集器(请参阅What's the most efficient way to retrieve all matching documents from a query in Lucene, unsorted?)以及可能使用Solr / Elasticsearch中的Cursors / Scrolling来执行此操作,但我想知道是否有任何其他技术经过专门优化对于这个问题?
答案 0 :(得分:3)
据我了解Lucene / Solr的强大功能,Sphinx和ElasticSearch将以极快的速度回馈TOP文档,但它们并非真正打算回赠所有文档。
实际上,这曾经是真实的,但近年来变得更好了。当涉及其他软件选项时,我会推荐其他人,但Lucene在4.x系列的早期确实得到了一些改进,以便用光标进行高效的深度分页。
Elasticsearch有一个特别好的API:Scrolling Search。要使用它,请使用scroll
参数提供搜索查询。然后它返回一个scroll_id
光标,用于为每个页面发出后续请求。
如果您不关心排序,只想要返回所有文档,那么您还可以指定搜索类型scan
。这将以最有效的顺序返回所有文档,而不应用特定的排序。
我在这里隐瞒了一些细节,您需要查看Scrolling Search文档以获得更详尽的说明。
Solr还支持SOLR-5463中Solr 4.7的深度分页。它增加了对cursorMark
参数的支持,以便与搜索请求一起使用。然后Solr返回指向每个后续页面的nextCursorMark
。
请参阅Solr的Pagination of Results文档中的“使用游标”部分。
听起来OP已经熟悉了这些选项,但我认为为了其他有类似问题的人而言,值得充实。
同样有趣:my take on the mechanics and efficiency of an Elasticsearch scrolling search。
答案 1 :(得分:0)
如果对处理相同问题的任何人都有帮助,这就是我要解决的问题。
我正在使用Lucene和一个自定义收集器,它存储所有匹配的ID,无需任何处理:
class IDCollector : Collector
{
// Offset for multiple reader
private int docBase;
// Stores IDs for all hits
public List<int> HitList { get; set; }
public IDCollector()
{
this.HitList = new List<int>(INITIAL_CAPACITY);
}
public override void Collect(int doc)
{
HitList.Add(doc + docBase);
}
// Order of docs does not matter
public override bool AcceptsDocsOutOfOrder { get { return true; } }
// Default implementation, docBase is the offset from reader
public override void SetNextReader(IndexReader reader, int docBase)
{
this.docBase = docBase;
}
// Scoring is not necessary
public override void SetScorer(Scorer scorer) { }
}
这样,对于像term1* OR term2* OR term3* OR term4*
这样的查询,可以在大约5.5秒内收集每个匹配文档的所有〜30mio ID。
不幸的是,但可能无法避免,即使没有对点击进行任何评分,排序或类似处理,搜索速度也非常依赖于点击次数。