Join 多层次连接解决方案

Join 多层次连接解决方案,join,solr,Join,Solr,嗨,我有一个三级树结构的数据。当用户搜索第三级节点时,我可以使用SOlr JOIN获取根节点吗 例如— PATIENT1 -> FirstName1 -> LastName1 -> DOCUMENTS1_1 -> document_type1_1 -> document_description1_1 -> document_value1_1

嗨,我有一个三级树结构的数据。当用户搜索第三级节点时,我可以使用SOlr JOIN获取根节点吗

例如—

    PATIENT1
       -> FirstName1
       -> LastName1
       -> DOCUMENTS1_1
            -> document_type1_1
            -> document_description1_1
            -> document_value1_1
            -> CODE_ITEMS1_1_1
                -> Code_id1_1_1
                -> code1_1_1
            -> CODE_ITEMS1_1_1
                -> Code_id1_1_2
                -> code1_1_2
       -> DOCUMENTS1_2
            -> document_type1_2
            -> document_description1_2
            -> document_value1_2
            -> CODE_ITEMS1_2_1
                -> Code_id1_2_1
                -> code1_2_1
            -> CODE_ITEMS1_2_2
                -> Code_id1_2_2
                -> code1_2_2
    PATIENT2
       -> FirstName2
       -> LastName2
       -> DOCUMENTS2_1
            -> document_type2_1
            -> document_description2_1
            -> document_value2_1
            -> CODE_ITEMS2_1_1
                -> Code_id2_1_1
                -> code2_1_1
            -> CODE_ITEMS2_1_2
                -> Code_id2_1_2
                -> code2_1_2
我要搜索代码项并返回与代码项搜索条件匹配的所有患者。如何做到这一点。是否可以实现两次联接。第一个联接提供代码项搜索的所有文档,下一个联接提供所有患者

类似于SQL查询-

select * from patients where docID (select DOCID from DOCUMENTS where CODEID IN (select CODEID from CODE_ITEMS where CODE LIKE '%SEARCH_TEXT%'))

我真的不知道内部Solr连接是如何工作的,但知道RDB多个连接在大型数据集上效率极低,我可能最终会编写自己的连接,在完成正常搜索后,将获得根父级(当然,这种方法要求每个子文档都有一个对其根患者的引用)

如果你选择走这条路,我将发布一些例子。在我以前的一个Solr项目中,我遇到了类似的(更复杂的本体)问题

更简单的方法(解决此问题时更简单,而不是整个方法)是将模式的这一部分完全展平,并将所有信息(文档和代码项)存储到其父患者中,然后进行常规搜索。这更符合Solr(您必须以不同的方式看待Solr模式。它与常规RDB规范化模式完全不同,Solr鼓励数据冗余,以便您可以在没有连接的情况下快速搜索)

第三种方法是对具有代表性的数据集进行一些连接测试,看看搜索性能是如何受到影响的

最后,这实际上取决于您的整个设置和需求(当然还有测试结果)

编辑1: 我在几年前就这么做了,所以你必须弄清楚事情是否在这段时间发生了变化

1。创建自定义请求处理程序

为了完成完全干净的工作,我建议您定义自己的请求处理程序(在solrconfig.xml中),只需复制以


...
...

然后将
名称
更改为对用户有意义的内容,例如
/searchPatients
。 此外,将此部分添加到:

    <arr name="components">
            <str>patients</str>
            <str>facet</str>
            <str>mlt</str>
            <str>highlight</str>            
            <str>stats</str>
            <str>debug</str>
    </arr>

患者
方面
mlt
突出
统计数据
调试
2。创建自定义搜索组件

将此添加到solrconfig:

<searchComponent name="patients" class="org.apache.solr.handler.component.PatientQueryComponent"/>

创建PatientQueryComponent类:
以下源代码可能有错误,因为我在文本编辑器中编辑了我的原始源代码,并在未经测试的情况下发布了它,但重要的是您得到的是配方,而不是完成的源代码,对吗?我抛弃了缓存、延迟加载、prepare方法,只留下基本逻辑。您必须了解性能将如何受到影响,然后根据需要调整源代码。我的性能很好,但我的索引中总共有几百万个文档

公共类PatientQueryComponent扩展了SearchComponent{
...
@凌驾
公共无效进程(ResponseBuilder rb)引发IOException{
SolrQueryRequest req=rb.req;
SolrQueryResponse rsp=rb.rsp;
SolrParams params=req.getParams();
if(!params.getBool(组件名称,true)){
返回;
}
searcher=req.getSearcher();
//如果未设置,则将-1作为标志。
long-timeAllowed=(long)params.getInt(CommonParams.TIME_-ALLOWED,-1);
DocList initialSearchList=null;
solrindexearcher.QueryCommand cmd=rb.getQueryCommand();
cmd.setTimeAllowed(timeAllowed);
cmd.setSupersetMaxDoc(不限最大计数);
//消防标准查询
SolrIndexSearcher.QueryResult结果=新的SolrIndexSearcher.QueryResult();
searcher.search(结果,cmd);
initialSearchList=result.getDocList();
//设置用于保存患者ID的
List patientIds=new ArrayList();
DocIterator迭代器=initialSearchList.iterator();
int-id;
//循环搜索结果
while(iterator.hasNext()){
//添加您的if逻辑(单据类型,…)
id=iterator.nextDoc();
doc=searcher.doc(id);/,fields)您可以尝试惰性字段加载,只将patientID字段值加载到文档中
字符串patientId=doc.get(“patientId”)//位于子文档中并指向其根父级-patient的字段
patientIds.add(patientId);
}
//TermsFilter中所有唯一的患者ID
TermsFilter TermsFilter=新的TermsFilter();
任期;
for(字符串pid:patientIds){
term=新术语(“patient_ID”,pid);//对patient唯一(名称)并保存patientID的字段
术语过滤器。添加术语(术语);
}
//获取ID在TermsFilter中的所有患者
DocList patientsList=null;
patientsList=searcher.getDocList(new MatchAllDocsQuery(),searcher.convertFilter(termsFilter),null,0,1000);
long totalSize=initialSearchList.size()+patientsList.size();
logger.info(“总计:+totalSize”);
SolrDocumentList solrResultList=SolrPluginUtils.docListToSolrDocumentList(patientsList,searcher,null,null);
SolrDocumentList solrinitialist=SolrPluginUtils.docListToSolrDocumentList(initialSearchList,searcher,null,null);
//将患者添加到列表的末尾
for(SolrDocument父级:solrResultList){
solrinitialist.add(父级);
}
//替换初始结果作为响应
添加或替换结果(rsp,Solrinitialist);
addToLog(“hitsRef”,patientsList.size());
rb.setResult(result);
}
}

看看这篇文章:


实际上,您可以在SOLR 4.5中执行此操作,谢谢,我必须搜索3种类型的文档,因此最好是将其规范化并存储。你能更清楚地了解这家公司吗
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 );
    }
}