solr中的多级连接

时间:2012-07-27 21:29:05

标签: join solr

我有3级树结构的数据。当用户搜索第3级节点时,我可以使用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

我想搜索CODE_ITEM并返回符合代码项搜索条件的所有患者。如何才能做到这一点。是否可以实现两次连接。第一次连接为code_item搜索提供所有文档,下一次连接为所有患者提供。

类似于SQL查询 -

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

2 个答案:

答案 0 :(得分:1)

我真的不知道Solr内部如何加入工作,但是知道RDB多个连接在大型数据集上效率非常低,我可能最终会编写自己的org.apache.solr.handler.component.QueryComponent,在进行正常搜索之后获取root父级(当然,这种方法要求每个子doc都有对其根患者的引用)。

如果你选择走这条路,我会发布一些例子。我之前的Solr项目中有一个类似的(更复杂的 - 本体论)问题。

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

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

最后,它实际上取决于您的整体设置和要求(当然还有测试结果)。

编辑1: 我这几年回来了,所以你必须弄清楚事情是否会在平均时间内发生变化。

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

要完全清理作业,我建议您通过简单地复制以

开头的整个部分来定义您自己的Request处理程序(在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 );
    }
}

答案 1 :(得分:1)

看一下这篇文章:http://blog.griddynamics.com/2013/12/grandchildren-and-siblings-with-block.html

实际上你可以在SOLR 4.5

中完成