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 );
}
}