3

宗教、カースト、生年月日、食べ物の好み、喫煙/禁煙など、約 40 ~ 50 の質問をユーザーに尋ねる出会い系ポータルを作成しています。

年齢層、宗教の好み、喫煙の好みなど、ユーザーの好みについて同様の質問をしています。

私はそのような好みを約30-40持っています。

ここで、設定セットに基づいて一致をユーザーに表示したいと思います。MySQL のテーブルとインデックスをどのように設計すればよいか知りたいです。

user_preferences の 1 つの大きなテーブルを作成し、すべての設定インデックスを作成する必要があります。複数の列インデックスまたはマージ インデックスである必要があります。

一連の質問を異なるテーブルに保持し、データを取得するときにそれらを結合する必要がありますか? メートル

4

2 に答える 2

1

私はこのようなものを見ます:

ここに画像の説明を入力

questions回答する質問のリストです。期待される回答のタイプ (例: からの検索、日付、数値、テキストなど)question_typeを示す列挙型です。入力されるデータのタイプは何でもかまいません。question_choicesこれは、この表の他の列とともに、入力フォームを駆動できます。

question_answers質問に対する定義済みの回答のリストが含まれています (宗教、髪の色、目の色などの定義済みのリストなど)。これを使用して、入力フォームに値のドロップダウン リストを作成できます。

usersかなり自明です。

user_characteristicsアンケートに対する私の回答のリストが含まれています。このweight列は、私を探している誰かが同じ答えを持っていることが、私にとってどれほど重要かを示しています。question_choices_idテーブルから作成された選択リストから回答が得られた場合、 が入力されますquestion_choices。それ以外の場合question_choices_idは NULL になります。value列の場合は逆です。valueテーブルから構築された選択リストから回答が得られた場合、NULL になりますquestion_choices。それ以外の場合valueは、質問に対するユーザーの手作りの回答が含まれます。

user_preferences私が探している人のためのアンケートへの回答が含まれています。このweight列は、探している人が同じ答えを持っていることが、私にとってどれほど重要かを示しています。question_choices_idおよび列はvalue、表と同じように動作しuser_characteristicsます。

私の一致を見つけるためのSQLは次のようになります。

SELECT uc.id
      ,SUM(up.weight)                   AS my_weighted_score_of_them
      ,SUM(uc.weight)                   AS their_weighted_score_of_me
      ,SUM(up.weight) + SUM(uc.weight)  AS combined_weighted_score
  FROM user_preferences        up
  JOIN user_characteristics    uc
    ON uc.questions_id           = up.questions_id
   AND uc.question_choices_id    = up.question_choices_id
   AND uc.value                  = up.value
   AND uc.users_id              != up.users_id
 WHERE up.users_id               = me.id
 GROUP BY uc.id
 ORDER BY SUM(up.weight) + SUM(uc.weight) DESC
         ,SUM(up.weight) DESC
         ,SUM(uc.weight) DESC

パフォーマンス上の理由から、user_characteristics (id、question_id、question_choices_id、value、および user_id) のインデックスと user_preferences (id、question_id、question_choices_id、value、および user_id) のインデックスをお勧めします。

上記の SQL は、リクエストを行ったユーザーを除くすべてのユーザーに対して 1 つの行を返すことに注意してください。これは確かに望ましくありません。したがって、HAVING SUM(up.weight) + SUM(uc.weight) > :some_minimum_value結果をさらにフィルタリングするために追加するか、他の方法を検討することができます。

さらなる微調整には、回答を私と同じかそれ以上に評価する人のみを返すことが含まれる可能性があります (つまり、彼らの特徴的な体重は>=私の体重の好みの体重です.

于 2013-09-20T18:55:30.073 に答える
1

これはEAVの場合だと思います:

ここに画像の説明を入力

次のように、一致するユーザー ペアを降順 (最も一致するものから最も少ないものへ) で取得できるはずです。

SELECT *
FROM (
    SELECT U1.USER_ID, U2.USER_ID, COUNT(*) MATCH_COUNT
    FROM USER U1
        JOIN USER_PREFERENCE P1
            ON (U1.USER_ID = P1.USER_ID)
        JOIN USER_PREFERENCE P2
            ON (P1.NAME = P2.NAME AND P1.VALUE = P2.VALUE)
        JOIN USER U2
            ON (P2.USER_ID = U2.USER_ID)
    WHERE U1.USER_ID < U2.USER_ID -- To avoid matching the user with herself and duplicated pairs with flipped user IDs.
    GROUP BY U1.USER_ID, U2.USER_ID
) Q
ORDER BY MATCH_COUNT DESC

これは、設定を正確な値で一致させるだけです。範囲または列挙型の値に対して追加の「設定」テーブルを作成し、それにP1.VALUE = P2.VALUE応じて置き換えることができます。また、一致が USER テーブルのデータと一致する場合 (ユーザーの年齢が他のユーザーの希望する年齢範囲に該当するかどうかなど) は、まだ特別な処理が必要になる場合があります。

{NAME, VALUE}が役立つインデックスに注意してくださいP1.NAME = P2.NAME AND P1.VALUE = P2.VALUE。InnoDB テーブルはクラスター化されており、1 つの結果として、セカンダリ インデックスに PK フィールドのコピーが含まれます。この場合、インデックスがテーブルI1を完全にカバーします。MySQL が実際にそれを使用するかどうかは別の問題です - いつものように、クエリ プランを見て、代表的なデータを測定します...

于 2013-09-14T01:13:50.443 に答える