11

MYSQL を使用して、クエリによって返される各結果のスコアを生成しています。結果はスコア順に並べられます。

うまく機能していないように見える部分は、検索された各タグにスコアを追加して結果を割り当てようとしているときです。たとえば、「example」、「test」、および「tag」というタグを検索し、結果の 1 つが「example」、「test」、「someothertag」というタグに割り当てられているとします。スコアは 10 になるはずです。 2試合あるから。

実際に起こっていることは、一致するタグの数に関係なく、一致する場合は 5 のスコアを取得していることです。一致するタグがない場合は 0。

検索から生成されるクエリの 1 つの例を次に示します。

        SELECT DISTINCT results.*,
                    ( 
                        5*(MATCH(tags.name) AGAINST('"self employed"' IN BOOLEAN MODE)) +
            5*(MATCH(tags.name) AGAINST('"rental income"' IN BOOLEAN MODE)) +
            5*(MATCH(tags.name) AGAINST('"commission income"' IN BOOLEAN MODE)) +
            5*(MATCH(tags.name) AGAINST('"bankruptcy"' IN BOOLEAN MODE)) +
            5*(MATCH(tags.name) AGAINST('"condo approval"' IN BOOLEAN MODE)) +

                        1*usefulness + 
                        10*shares 
                    ) AS score 
        FROM results
        INNER JOIN categories c on results.ID = c.RESULT_ID
        INNER JOIN tags ON results.id = tags.result_id
        WHERE c.name in ('purchase', 'condo', 'va')
        AND ( tags.name = 'self employed' OR tags.name = 'rental income' OR tags.name = 'commission income' OR tags.name = 'bankruptcy' OR tags.name = 'condo approval'  )
        AND ( results.scope = 'all' OR results.scope = 'hi' )
        AND published = 1

        GROUP BY results.ID
        having count(distinct c.c_id) = 3
        ORDER BY score DESC 
        LIMIT 8 OFFSET 0
4

4 に答える 4

1

WHERESam Dufel のアドバイスによると、特に句で正確な文字列比較を使用しているため、おそらく全文検索は必要ありません。

さらに、 (節から推測される) resultsandの間の多対多の関係のために、同じクエリでとの両方を結合することは決してできないと思います。categoriesHAVING COUNT(c_id) = 3categoriestags

GROUP BYこの句がないと、指定された 1 つresultの に対して、一致する ごとに 1 つの行が取得されますcategory。一致するペア ( result, category) ごとに、一致する ごとに 1 つの行を取得しますtag.name。このような結果に対処する方法はないと思います。

私が提案するのは次のとおりです。

ステップ 1 : results3 つのカテゴリすべてに参加する

SELECT results.ID
FROM results
JOIN categories ON results.id = categories.result_id
WHERE categories.name IN ('purchase', 'condo', 'va')
GROUP BY results.ID
HAVING COUNT(DISTINCT c.c_id) = 3

ステップ 2results :一致する少なくとも 1 つの検索文字列のスコアを計算する

SELECT
    DISTINCT results.*, -- DISTINCT is redundant because of the GROUP BY clause
    ( 
        5*(COUNT(tags.result_id)) + -- you actually want to count the number of matches!
        1*usefulness +  -- warning, see below 
        10*shares       -- warning, see below
    ) AS score 
FROM results
INNER JOIN tags ON results.id = tags.result_id
WHERE
    tags.name = 'self employed'
    OR tags.name = 'rental income'
    OR tags.name = 'commission income'
    OR tags.name = 'bankruptcy'
    OR tags.name = 'condo approval'
GROUP BY results.ID

ステップ 3 : すべてをまとめる

SELECT
    results.*,
    ( 
        5*(COUNT(tags.result_id)) +
        1*usefulness +  -- warning, see below 
        10*shares       -- warning, see below
    ) AS score 
FROM (
        SELECT results.id
        FROM results
        JOIN categories ON results.id = categories.result_id
        WHERE
            categories.name IN ('purchase', 'condo', 'va')
            AND ( results.scope = 'all' OR results.scope = 'hi' )
            AND published = 1
        GROUP BY results.id
        HAVING COUNT(DISTINCT categories.c_id) = 3
) AS results_subset
JOIN results ON results_subset.id = results.id
JOIN tags ON results.id = tags.result_id
WHERE
    tags.name = 'self employed'
    OR tags.name = 'rental income'
    OR tags.name = 'commission income'
    OR tags.name = 'bankruptcy'
    OR tags.name = 'condo approval'
GROUP BY results.ID

条件 WHERE onscopeとを含めることを選択した場所に注意してくださいpublished。この選択は、フィルターはできるだけ早く宣言する必要があるという原則に基づいています。それらを外側のクエリに配置すると、パフォーマンスが向上する可能性がありますが、実際にはカーディナリティに依存します。

警告: フィールドusefulnessとは、集計関数に含まれない関数sharesの一部ではありません。GROUP BYこれはMySQL で許可されていますが、非常に危険です。usefulnessおよびが(GROUP BY されているテーブル)shares以外のテーブルに属している場合、クエリで返される値は未定義です。result

于 2013-05-03T15:49:58.813 に答える
0

あなたのクエリは複雑すぎると思います。これを試して:

SELECT
    results.*,
    5 * count(distinct tags.name) + 1*usefulness + 10*shares AS score 
FROM results
JOIN categories c on results.ID = c.RESULT_ID
    AND c.name in ('purchase', 'condo', 'va')
JOIN tags ON results.id = tags.result_id
    AND tags.name in ('self employed', 'rental income', 'commission income', 'bankruptcy', 'condo approval')
WHERE results.scope in ('all', 'hi')
AND published = 1
GROUP BY 1, 2, 3, 4, 5 -- list as many numbers here as there are columns in "results" 
HAVING count(distinct c.c_id) = 3
ORDER BY score DESC 
LIMIT 8 OFFSET 0

あなたが抱えていた重要な問題の 1 つはグループ化でした。適切に機能させるには、テーブルのすべての列に名前を付けるか、選択した位置で参照する必要がありresultsます。テーブル スキーマが指定されていないため、何を記述すればよいかわかりません。私は 5 つの列を推測したため、GROUP BY 1, 2, 3, 4, 5ですが、これが正しいことを確認する必要があります。

ORs に変更して s を整理しました。INこれにより、そのようなインデックスが存在する場合、これらの列でインデックスを使用できるようになります (「OR」はインデックスを使用しません)。

WHERE節の条件のいくつかを、JOIN意味のある条件に移動しました。これにより、パフォーマンスが向上するはずです。

于 2013-05-09T14:41:18.847 に答える