sql >> Database >  >> RDS >> Mysql

Top 'n' resultaten voor elk zoekwoord

Aangezien je het schema voor results niet hebt gegeven , ik neem aan dat het dit is of zeer vergelijkbaar (misschien extra kolommen):

create table results (
  id int primary key,
  user int,
    foreign key (user) references <some_other_table>(id),
  keyword varchar(<30>)
);

Stap 1: aggregeren op keyword/user zoals in uw voorbeeldzoekopdracht, maar voor alle zoekwoorden:

create view user_keyword as (
  select
    keyword,
    user,
    count(*) as magnitude
  from results
  group by keyword, user
);

Stap 2: rangschik elke gebruiker binnen elke zoekwoordgroep (let op het gebruik van de subquery om de rijen te rangschikken):

create view keyword_user_ranked as (
  select 
    keyword,
    user,
    magnitude,
    (select count(*) 
     from user_keyword 
     where l.keyword = keyword and magnitude >= l.magnitude
    ) as rank
  from
    user_keyword l
);

Stap 3: selecteer alleen de rijen waar de rangorde kleiner is dan een getal:

select * 
from keyword_user_ranked 
where rank <= 3;

Voorbeeld:

Gebruikte basisgegevens:

mysql> select * from results;
+----+------+---------+
| id | user | keyword |
+----+------+---------+
|  1 |    1 | mysql   |
|  2 |    1 | mysql   |
|  3 |    2 | mysql   |
|  4 |    1 | query   |
|  5 |    2 | query   |
|  6 |    2 | query   |
|  7 |    2 | query   |
|  8 |    1 | table   |
|  9 |    2 | table   |
| 10 |    1 | table   |
| 11 |    3 | table   |
| 12 |    3 | mysql   |
| 13 |    3 | query   |
| 14 |    2 | mysql   |
| 15 |    1 | mysql   |
| 16 |    1 | mysql   |
| 17 |    3 | query   |
| 18 |    4 | mysql   |
| 19 |    4 | mysql   |
| 20 |    5 | mysql   |
+----+------+---------+

Gegroepeerd op zoekwoord en gebruiker:

mysql> select * from user_keyword order by keyword, magnitude desc;
+---------+------+-----------+
| keyword | user | magnitude |
+---------+------+-----------+
| mysql   |    1 |         4 |
| mysql   |    2 |         2 |
| mysql   |    4 |         2 |
| mysql   |    3 |         1 |
| mysql   |    5 |         1 |
| query   |    2 |         3 |
| query   |    3 |         2 |
| query   |    1 |         1 |
| table   |    1 |         2 |
| table   |    2 |         1 |
| table   |    3 |         1 |
+---------+------+-----------+

Gebruikers gerangschikt binnen zoekwoorden:

mysql> select * from keyword_user_ranked order by keyword, rank asc;
+---------+------+-----------+------+
| keyword | user | magnitude | rank |
+---------+------+-----------+------+
| mysql   |    1 |         4 |    1 |
| mysql   |    2 |         2 |    3 |
| mysql   |    4 |         2 |    3 |
| mysql   |    3 |         1 |    5 |
| mysql   |    5 |         1 |    5 |
| query   |    2 |         3 |    1 |
| query   |    3 |         2 |    2 |
| query   |    1 |         1 |    3 |
| table   |    1 |         2 |    1 |
| table   |    3 |         1 |    3 |
| table   |    2 |         1 |    3 |
+---------+------+-----------+------+

Alleen top 2 van elk zoekwoord:

mysql> select * from keyword_user_ranked where rank <= 2 order by keyword, rank asc;
+---------+------+-----------+------+
| keyword | user | magnitude | rank |
+---------+------+-----------+------+
| mysql   |    1 |         4 |    1 |
| query   |    2 |         3 |    1 |
| query   |    3 |         2 |    2 |
| table   |    1 |         2 |    1 |
+---------+------+-----------+------+

Merk op dat wanneer er gelijkspel is -- zie gebruikers 2 en 4 voor trefwoord "mysql" in de voorbeelden -- alle partijen in het gelijkspel de "laatste" rang krijgen, d.w.z. als de 2e en 3e gelijk zijn, krijgen beide rang 3 toegewezen.

Prestaties:het toevoegen van een index aan de trefwoorden en gebruikerskolommen zal helpen. Ik heb een tabel die op een vergelijkbare manier wordt opgevraagd met 4000 en 1300 verschillende waarden voor de twee kolommen (in een tabel met 600000 rijen). U kunt de index als volgt toevoegen:

alter table results add index keyword_user (keyword, user);

In mijn geval daalde de zoektijd van ongeveer 6 seconden naar ongeveer 2 seconden.



  1. Gegevensafknotting:gegevens te lang voor kolom 'logo' op rij 1

  2. Opgeslagen procedure uitvoeren in MySQL Workbench

  3. Hoe NULL-waarden in datetime-velden in MySQL op te slaan?

  4. Hoe stel je een standaard pager in voor de MySQL-client?