1

こんにちは、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 を検索して、コード項目の検索条件に一致するすべての患者を返したいと考えています。これはどのように行うことができますか。結合を 2 回実装することは可能ですか。最初の結合は 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%'))
4

2 に答える 2

2

Solr の結合が内部でどのように機能するかはよくわかりませんが、RDB の複数の結合は大きなデータ セットでは非常に非効率的であることを知っているため、おそらく、独自のorg.apache.solr.handler.component.QueryComponentを作成することになるでしょう。通常の検索を行い、ルートの親を取得します (もちろん、このアプローチでは、各子ドキュメントがそのルートの患者への参照を持っている必要があります)。

このパスを選択した場合は、いくつかの例を投稿します。以前の Solr プロジェクトの 1 つで、同様の (より複雑なオントロジー) 問題が発生しました。

より簡単な方法 (アプローチ全体ではなく、この問題の解決に関してはより簡単です) は、スキーマのこの部分を完全にフラット化し、すべての情報 (ドキュメントとコード項目) をその親患者に格納し、通常の検索を行うことです。これは、Solr とより一致しています (Solr スキーマを別の方法で見る必要があります。通常の RDB 正規化スキーマとはまったく異なります。Solr はデータの冗長性を促進するため、結合なしで盲目的に高速に検索できます)。

3 番目のアプローチは、代表的なデータ セットでいくつかの結合テストを行い、検索パフォーマンスがどのように影響を受けるかを確認することです。

最終的には、セットアップ全体と要件 (そしてもちろんテスト結果) に大きく依存します。

EDIT 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 クラスを作成します
。元のソースをテキスト エディターで編集し、テストせずに投稿したため、次のソースにはエラーがある可能性がありますが、重要なことは、完成したソースではなく、レシピを取得することですよね? キャッシング、遅延読み込み、prepare メソッドを捨てて、基本的なロジックだけを残しました。パフォーマンスがどのように影響を受けるかを確認し、必要に応じてソースを微調整する必要があります。パフォーマンスは良好でしたが、インデックスには合計で数百万のドキュメントがありました。

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 );
    }
}
于 2012-07-28T00:59:15.040 に答える
1

この投稿をご覧ください: http://blog.griddynamics.com/2013/12/grandchildren-and-siblings-with-block.html

実際にはSOLR 4.5でそれを行うことができます

于 2013-12-29T14:29:35.960 に答える