我真的不知道 Solr 连接内部是如何工作的,但是知道 RDB 多重连接在大型数据集上效率极低,我可能最终会编写自己的org.apache.solr.handler.component.QueryComponent之后进行正常搜索,获取根父(当然,这种方法要求每个子文档都有对其根患者的引用)。
如果您选择走这条路,我将发布一些示例。在我之前的一个 Solr 项目中,我遇到了类似的(更复杂的本体)问题。
更简单的方法(在解决这个问题时更简单,而不是整个方法)是完全扁平化架构的这一部分并将所有信息(文档和代码项)存储到其父患者中,然后进行常规搜索。这更符合 Solr(您必须以不同的方式查看 Solr 架构。它与您的常规 RDB 规范化架构完全不同,Solr 鼓励数据冗余,因此您可以在没有连接的情况下快速搜索)。
第三种方法是对代表性数据集进行一些连接测试,看看搜索性能如何受到影响。
最后,这实际上取决于您的整个设置和要求(当然还有测试结果)。
编辑1:
我在几年前做过,所以你必须弄清楚事情是否同时发生了变化。
1.创建自定义请求处理程序
要完成完全干净的工作,我建议您通过简单地复制以开头的整个部分来定义自己的请求处理程序(在 solrconfig.xml 中)
<requestHandler name="/select" class="solr.SearchHandler">
...
...
</requestHandler>
然后更改name
为对您的用户有意义的内容,例如/searchPatients
. 另外,在里面添加这个部分:
<arr name="components">
<str>patients</str>
<str>facet</str>
<str>mlt</str>
<str>highlight</str>
<str>stats</str>
<str>debug</str>
</arr>
2.创建自定义搜索组件
将此添加到您的 solrconfig:
<searchComponent name="patients" class="org.apache.solr.handler.component.PatientQueryComponent"/>
创建 PatientQueryComponent 类:
以下源可能有错误,因为我在文本编辑器中编辑了我的原始源并在没有测试的情况下发布了它,但重要的是你得到的是配方,而不是完成的源,对吗?我抛弃了缓存、延迟加载、准备方法,只留下了基本逻辑。您必须查看性能将如何受到影响,然后在需要时调整源。我的表现很好,但我的索引中总共有几百万个文档。
public class PatientQueryComponent extends SearchComponent {
...
@Override
public void process(ResponseBuilder rb) throws IOException {
SolrQueryRequest req = rb.req;
SolrQueryResponse rsp = rb.rsp;
SolrParams params = req.getParams();
if (!params.getBool(COMPONENT_NAME, true)) {
return;
}
searcher = req.getSearcher();
// -1 as flag if not set.
long timeAllowed = (long)params.getInt( CommonParams.TIME_ALLOWED, -1 );
DocList initialSearchList = null;
SolrIndexSearcher.QueryCommand cmd = rb.getQueryCommand();
cmd.setTimeAllowed(timeAllowed);
cmd.setSupersetMaxDoc(UNLIMITED_MAX_COUNT);
// fire standard query
SolrIndexSearcher.QueryResult result = new SolrIndexSearcher.QueryResult();
searcher.search(result, cmd);
initialSearchList = result.getDocList();
// Set which'll hold patient IDs
List<String> patientIds = new ArrayList<String>();
DocIterator iterator = initialSearchList.iterator();
int id;
// loop through search results
while(iterator.hasNext()) {
// add your if logic (doc type, ...)
id = iterator.nextDoc();
doc = searcher.doc(id); // , fields) you can try lazy field loading and load only patientID filed value into the doc
String patientId = doc.get("patientID") // field that's in child doc and points to its root parent - patient
patientIds.add(patientId);
}
// All all unique patient IDs in TermsFilter
TermsFilter termsFilter = new TermsFilter();
Term term;
for(String pid : patientIds){
term = new Term("patient_ID", pid); // field that's unique (name) to patient and holds patientID
termsFilter.addTerm(term);
}
// get all patients whose ID is in TermsFilter
DocList patientsList = null;
patientsList = searcher.getDocList(new MatchAllDocsQuery(), searcher.convertFilter(termsFilter), null, 0, 1000);
long totalSize = initialSearchList.size() + patientsList.size();
logger.info("Total: " + totalSize);
SolrDocumentList solrResultList = SolrPluginUtils.docListToSolrDocumentList(patientsList, searcher, null, null);
SolrDocumentList solrInitialList = SolrPluginUtils.docListToSolrDocumentList(initialSearchList, searcher, null, null);
// Add patients to the end of the list
for(SolrDocument parent : solrResultList){
solrInitialList.add(parent);
}
// replace initial results in response
SolrPluginUtils.addOrReplaceResults(rsp, solrInitialList);
rsp.addToLog("hitsRef", patientsList.size());
rb.setResult( result );
}
}