多重連結データ検索 | KandaSearch Community Support Forum

多重連結データ検索

トピック作成者:ks-solruserml-bot (2025/03/01 23:03 投稿)
9
OpenOpen

(The bot translated the original post https://lists.apache.org/thread/5k9ffxsc1k21vv21v8nmq0yypw1wpnyt into Japanese and reposted it under Apache License 2.0. The copyright of posted content is held by the original poster.)

こんにちは、皆さん。

明確な解決策がありそうな質問なのですが、どこを探しても答えが見つかりません。

本と著者のデータベースがあるとします。各本には複数の著者がいる可能性があり、各著者は複数の本を執筆している場合があります。本のタイトルと著者名の両方を同時に検索し、キーワードが本のタイトルまたは著者名のどちらに含まれていても、本とその著者のリストを結果として表示したいと考えています。

SQLで表現すると、次のようなクエリになります。

SELECT *
FROM books, books_authors, authors
WHERE
books.id = books_authors.bookid
AND books_authors.authorid = authors.id
AND ( books.title LIKE :search_key OR authors.name LIKE :search_key )

私が思いつく唯一の方法は、まず検索を実行して該当する本と著者を取得し、その後、最初のクエリで見つかった本や著者に関連するすべての本と著者を取得するために別のクエリを実行することです。

これをより賢く実現する方法はあるでしょうか?ベストプラクティスがあれば教えてください。

返信投稿者:ks-solruserml-bot (2025/03/01 23:04 投稿)

本は「ドキュメント」であり、タイトルと著者を別々のフィールドとして持ちます。

通常、ドキュメントには「大規模検索」用のフィールドがあり、デフォルト設定では_text_と呼ばれます。

著者リストとタイトルの両方を_text_にコピーし、_text_で検索し、著者やタイトルでファセットを実行してください。

— Dima

返信投稿者:ks-solruserml-bot (2025/03/01 23:04 投稿)

ご提案ありがとうございます。しかし、その方法ではうまくいきません。なぜなら、同じ名前の著者が複数存在し、IDによってのみ区別される場合があるからです。

もし著者の名前を変更する場合、どの著者を変更し、どの著者をそのままにするべきか判断できません。

さらに、外部識別子などの追加の著者情報があり、それを著者に正しく紐付ける必要がある場合もあります。

返信投稿者:ks-solruserml-bot (2025/03/01 23:04 投稿)

こんにちは、
以下をご覧ください。

これはデータ統合やETLの課題です。
注意点として、Solr などのドキュメントデータベースは、ストアドビューやデータマートを意味します。
私たちは、特定の操作(検索、フィルタリング、集計)を最適化するために、データを非正規化してこのようなストアドビューを構築します。
しかし、このような派生データの表現には、構築や更新に伴うコストが発生します。

ドキュメントデータベースでは、即席の RDBMS の結合(JOIN)は基本的に利用できません(上記の理由による)。
ただし、以下のような類似の操作があり、それぞれに制約があります。

  • {!parent}
  • {!join}
  • その他の方法

--
よろしくお願いします、
Mikhail Khludnev

返信投稿者:ks-solruserml-bot (2025/03/01 23:04 投稿)

Solr はデータの主要なストレージや操作には最適な選択肢ではありません。
もしデータがそのように変更可能(ミュータブル)であるなら、RDB に保存して編集を行い、その後 Solr に取り込んで検索に利用するのがよいでしょう。

この手法には「CQRS(Command Query Responsibility Segregation)」というバズワードがあります。

— Dima

返信投稿者:ks-solruserml-bot (2025/03/01 23:05 投稿)

Solr を主要なデータストアとして使用しないでください。Solr はデータベースではありません。すべての関係を適切に追跡し、正しく更新できるように、データはリレーショナルデータベースに保存してください。

必要なフィールドを抽出し、それを Solr にロードします。

この処理は、毎日フルダンプしてロードするジョブとして実行できます。私が Chegg で何百万冊もの書籍を扱っていたときは、その方法を採用しました。シンプルかつ高速で、全体の処理を 1 時間以内に完了させることが可能です。

all-in-one_text_ フィールドを使用する代わりに、edismax を使用し、異なるフィールドに異なる重みを設定する方法もあります。たとえば、フレーズマッチに対してより高い重みを付ける場合、以下のように設定できます。

<qf>title^4 authors</qf>
<pf>title^8 authors^2</qf>

wunder
Walter Underwood
wunder@wunderwood.org
http://observer.wunderwood.org/ (私のブログ)

返信投稿者:ks-solruserml-bot (2025/03/01 23:05 投稿)

私も同意します。Solr を主要なデータストアとして使用すべきではありません。しかし、1 回のクエリでできるだけ多くの情報を取得できるのは便利だと思います。

現在、以下のような解決策を試しています。
各 Solr ドキュメントに otherids というマルチバリューのフィールドを持たせ、書籍には関係するすべての著者の ID を、著者には自身が執筆したすべての書籍の ID を含めるようにします。また、各ドキュメントは自身の ID も otherids に含めます。これにより、単一の結合クエリで必要な情報をすべて取得できるようになります。

この方法に何か欠点があると思いますか?

返信投稿者:ks-solruserml-bot (2025/03/01 23:05 投稿)

いくつか気になる点があります。

まず、長年の経験から、「other_ids」のようなフィールド名は避けたほうがよいと思います。「other」(その他)という言葉の意味は文脈によって変わるからです。今は明確に理解できているかもしれませんが、他の人にとっても分かりやすいでしょうか?1 年後の自分にとっても明確でしょうか?もし 3 番目の関係が出てきた場合、「the_other_other_ids」というフィールドを追加するのでしょうか?フィールド名はその内容を正確に表すべきです。たとえば、書籍には「author_ids」、著者には「book_ids」というフィールドを持たせると、データスキーマがそのまま意味を持つようになり、動作ロジックを参照する必要がなくなります。

次に、Solr の「ネストされたドキュメント(Nested Documents)」について調べてみてください。我々も別の用途で活用していますが、非常にうまく機能しています。Solr のネストドキュメントのページによると、「ドキュメント間の関係をインデックスすることで、同等の 'クエリ時結合(query-time join)' よりもはるかに高速なクエリが可能になる」とのことなので、まさに求めているものかもしれません。

最後に、おそらく早すぎる最適化をしているのではないかと感じます。Solr への追加のクエリを恐れる必要はありません。Solr は非常に高速です。エンジニアリングの基本として、実際に問題があるかどうかを測定する前に、過度に最適化しようとするべきではありません。初回のクエリとフォローアップのクエリが必要なシンプルなソリューションでも、設計・実装・テスト・調整に何週間もかかるような複雑なソリューションと比べて、速度差はほとんどないかもしれません。

少しでも参考になれば幸いです。

Andrew Witt

返信投稿者:ks-solruserml-bot (2025/03/01 23:06 投稿)

まず、長年の経験から、「other_ids」のようなフィールド名は避けたほうがよいと思います。「other」(その他)という言葉の意味は文脈によって変わるからです。今は明確に理解できているかもしれませんが、他の人にとっても分かりやすいでしょうか?1 年後の自分にとっても明確でしょうか?もし 3 番目の関係が出てきた場合、「the_other_other_ids」というフィールドを追加するのでしょうか?フィールド名はその内容を正確に表すべきです。たとえば、書籍には「author_ids」、著者には「book_ids」というフィールドを持たせると、データスキーマがそのまま意味を持つようになり、動作ロジックを参照する必要がなくなります。

同意します。データベース設計の観点から見れば、これは明らかに優れたアプローチですが、Solr の join クエリパーサーでは使用できません。なぜなら、join クエリパーサーは結合元のフィールドとして 1 つのフィールドしか指定できないためです。ただし、join クエリパーサーが複数のフィールドを結合元としてサポートするように更新されれば、この方法が最適なアプローチになるでしょう。

次に、Solr の「ネストされたドキュメント(Nested Documents)」について調べてみてください。我々も別の用途で活用していますが、非常にうまく機能しています。Solr のネストドキュメントのページによると、「ドキュメント間の関係をインデックスすることで、同等の 'クエリ時結合(query-time join)' よりもはるかに高速なクエリが可能になる」とのことなので、まさに求めているものかもしれません。

この方法が理にかなっているのは確かですが、先ほど述べたように、1 冊の本には複数の著者がいる場合があり、1 人の著者が複数の本を執筆することもあるため、ネストドキュメント(Nested Documents)は適用できません。

最後に、おそらく早すぎる最適化をしているのではないかと感じます。Solr への追加のクエリを恐れる必要はありません。Solr は非常に高速です。エンジニアリングの基本として、実際に問題があるかどうかを測定する前に、過度に最適化しようとするべきではありません。初回のクエリとフォローアップのクエリが必要なシンプルなソリューションでも、設計・実装・テスト・調整に何週間もかかるような複雑なソリューションと比べて、速度差はほとんどないかもしれません。

私は、よりエレガントな解決策を探しています。そして、おそらくそれを見つけたと思います。ただし、パフォーマンスが向上するかどうかはまだ確認できていません。理論的には高速化されるはずですが、なぜなら Solr が内部で処理することで、私が外部で行う必要がなくなるためです。よりエレガントなソリューションは、構築や改良も容易になるはずです。

返信投稿者:ks-solruserml-bot (2025/03/01 23:06 投稿)

Solr におけるエレガントな解決策は「フラットなスキーマ」です。あなたが行っているのは「データベース設計」ではなく、「検索スキーマ設計」です。これらはまったく異なるものです。

結合(Joins)は絶対に行わないでください。

検索が必要なフィールドを列挙し、それらを indexed に設定してください。データ量が少ない(100 万件未満)の場合、デバッグを容易にするために stored にするのも有効です。

表示が必要なフィールドを列挙し、それらを stored に設定してください。ただし、indexed にはしないでください。

元のデータベース内の関連データが更新されたら、Solr にドキュメントを再ロードしてください。500 万~1000 万件程度のデータであれば、1 日 1 回すべてを再ロードするのは現実的な方法です。本のデータはそれほど頻繁には変わらないでしょう。

私は Netflix の検索を担当していましたが、それは本の検索と大きくは変わりません。また、Chegg で教科書検索のシステムを運用していました。

wunder
Walter Underwood
wunder@wunderwood.org
http://observer.wunderwood.org/ (私のブログ)

トピックへ返信するには、ログインが必要です。

KandaSearch

Copyright © 2006-2025 RONDHUIT Co, Ltd. All Rights Reserved.

投稿の削除

この投稿を削除します。よろしいですか?