2015-09-24 4 views
14

Ich habe eine Tabelle namens results mit 5 Spalten.Wie finde ich die beliebtesten Wortvorkommen in MySQL?

Ich möchte die title Spalte verwenden, um Zeilen zu finden, die sagen: WHERE title like '%for sale%' und dann die beliebtesten Wörter in dieser Spalte auflisten. Einer wäre for und ein anderer wäre sale, aber ich möchte sehen, welche anderen Wörter damit korrelieren.

Beispieldaten:

title 
cheap cars for sale 
house for sale 
cats and dogs for sale 
iphones and androids for sale 
cheap phones for sale 
house furniture for sale 

Ergebnisse (einzelne Wörter):

for 6 
sale 6 
cheap 2 
and 2 
house 2 
furniture 1 
cars 1 
etc... 
+2

Ihre Frage ist sehr mehrdeutig. Bitte geben Sie Beispieldaten und gewünschte Ergebnisse an. –

+1

mögliches Duplikat von [MySQL match() against() - nach Relevanz und Spalte sortieren?] (Http://stackoverflow.com/questions/6259647/mysql-match-against-order-by-relevance-and-column) Nicht ein genaues Duplikat, aber es beantwortet Ihre Frage – AgeDeO

+0

@GordonLinoff aktualisiert – User

Antwort

7

Sie sich also mit einigen String-Manipulation extrahieren kann. Unter der Annahme, haben Sie eine Tabelle Zahlen und Wörter durch einzelne Leerzeichen getrennt sind:

select substring_index(substring_index(r.title, ' ', n.n), ' ', -1) as word, 
     count(*) 
from results r join 
    numbers n 
    on n.n <= length(title) - length(replace(title, ' ', '')) + 1 
group by word; 

Wenn Sie keine Zahlen Tabelle haben, können Sie eine manuell konstruieren mit einer Unterabfrage:

from results r join 
    (select 1 as n union all select 2 union all select 3 union all . . . 
    ) n 
    . . . 

Die SQL Fiddle (mit freundlicher Genehmigung von @GrzegorzAdamKowalski) ist here.

+0

Kannst du das in eine SQL-Geige legen? – User

+2

Es scheint nicht richtig zu funktionieren. Überprüfen Sie es: http://sqlfiddle.com/#!9/b0749/2 –

+1

@GrzegorzAdamKowalski. . . Danke Danke. Ich hatte den Vergleich rückwärts. Fixed und Triple Danke für die SQL Fiddle. –

0

aktualisieren

Idee genommen von https://stackoverflow.com/a/17942691/98491

Diese Abfrage auf meinem Rechner funktioniert (MySQL 5.7) , Sqlfiddle meldet jedoch einen Fehler. Die Grundidee ist, dass Sie entweder eine Tabelle mit Zahlen von 1 bis zum maximalen Wortvorkommen (wie 4) in Ihrem Feld erstellen sollten oder wie ich es tat, verwenden Sie UNION 1 .. 4 zur Vereinfachung.

CREATE TABLE products (
    `id` int, 
    `name` varchar(45) 
); 

INSERT INTO products 
    (`id`, `name`) 
VALUES 
    (1, 'for sale'), 
    (2, 'for me'), 
    (3, 'for you'), 
    (4, 'you and me') 
; 

SELECT name, COUNT(*) as count FROM 
(
SELECT 
    product.id, 
    SUBSTRING_INDEX(SUBSTRING_INDEX(product.name, ' ', numbers.n), ' ', -1) name 
FROM 
    (
    SELECT 1 AS n 
    UNION SELECT 2 
    UNION SELECT 3 
    UNION SELECT 4 
) AS numbers 
    INNER JOIN products product 
    ON CHAR_LENGTH(product.name) 
    -CHAR_LENGTH(REPLACE(product.name, ' ', ''))>=numbers.n-1 
ORDER BY 
    id, n 
) 
AS result 
GROUP BY name 
ORDER BY count DESC 

Ergebnis wird

for | 3 
you | 2 
me | 2 
and | 1 
sale| 1 
+2

Sie könnten erwähnen, dass man dafür einen FULLTEXT-Index benötigen würde, der für MyISAM und seit 5.6 auch unterstützt wird. InnoDB – Kaii

+0

Warum gibt es keinen 'Teilstring', um die Zeichenkette in jedem Leerzeichen zu teilen? – User

+0

@User brauchen Sie nicht split 'match ... against' gibt Ihnen eine ganze Zahl zwischen null und eins, die für eine bessere Übereinstimmung höher ist. –

2

Dies würde Ihnen einzelne Wörter geben (Nur wenn ich verstehe, was Ihre single word bedeutet.):

Result 
-------- 
for 6 
sale 6 
house 2 
and 2 
cheap 2 
phones 1 
iphones 1 
dogs 1 
furniture 1 
cars 1 
androids 1 
cats 1 

Aber wenn die single word müssen Sie wie folgt aus::

result 
----------- 
for 6 sale 6 house 2 and 2 cheap 2 phones 1 iphones 1 dogs 1 furniture 1 cars 1 androids 1 cats 1 

einfach ändern Sie die Abfrage oben:

select group_concat(concat(val,' ',cnt) separator ' ') as result from(... 

select concat(val,' ',cnt) as result from(
    select (substring_index(substring_index(t.title, ' ', n.n), ' ', -1)) val,count(*) as cnt 
     from result t cross join(
     select a.n + b.n * 10 + 1 n 
     from 
       (select 0 as n union all select 1 union all select 2 union all select 3 
         union all select 4 union all select 5 union all select 6 
         union all select 7 union all select 8 union all select 9) a, 
       (select 0 as n union all select 1 union all select 2 union all select 3 
         union all select 4 union all select 5 union all select 6 
         union all select 7 union all select 8 union all select 9) b 
       order by n 
     ) n 
    where n.n <= 1 + (length(t.title) - length(replace(t.title, ' ', ''))) 
    group by val 
    order by cnt desc 
) as x 

Ergebnis sieht wie folgt sein sollte

+0

Was ist die Bedeutung von Union 1 bis 9? – User

+0

@Benutzer zählt 100. In diesem Fall würde die Unterabfrage 'n' also 1-100 zurückgeben. Werfen Sie einen Blick auf http://stackoverflow.com/questions/19073500/sql-split-comma-separated-row für weitere Details. – RubahMalam

+0

Wie lautet der Tabellenname? – User

0

SQL i s nicht gut für diese Aufgabe geeignet, zwar möglich, es gibt Einschränkungen (die Anzahl der Worte zum Beispiel)

eine schnelle PHP-Skript der gleiche Aufgabe zu tun, kann einfacher sein, langfristig zu nutzen (und wahrscheinlich schneller zu)

<?php 
$rows = [ 
    "cheap cars for sale", 
    "house for sale", 
    "cats and dogs for sale", 
    "iphones and androids for sale", 
    "cheap phones for sale", 
    "house furniture for sale", 
]; 

//rows here should be replaced by the SQL result 
$wordTotals = []; 
foreach ($rows as $row) { 
    $words = explode(" ", $row); 
    foreach ($words as $word) { 
     if (isset($wordTotals[$word])) { 
      $wordTotals[$word]++; 
      continue; 
     } 

     $wordTotals[$word] = 1; 
    } 
} 

arsort($wordTotals); 

foreach($wordTotals as $word => $count) { 
    echo $word . " " . $count . PHP_EOL; 
} 

Ausgabe

for 6 
sale 6 
and 2 
cheap 2 
house 2 
phones 1 
androids 1 
furniture 1 
cats 1 
cars 1 
dogs 1 
iphones 1 
+0

Python ist, was ich verwendet habe, um die Daten zu sammeln, aber das könnte funktionieren. Ich benutze PHP nicht so sehr, also etwas dagegen, den Code zu ändern, um die Zeilen aus der DB zu laden? – User

0

Hier arbeitet SQL Fiddle: http://sqlfiddle.com/#!9/0b0a0/32

ist mit zwei Tischen Lassen Sie beginnen - eine für Texte und eine für Zahlen:

CREATE TABLE text (`title` varchar(29)); 

INSERT INTO text 
    (`title`) 
VALUES 
    ('cheap cars for sale'), 
    ('house for sale'), 
    ('cats and dogs for sale'), 
    ('iphones and androids for sale'), 
    ('cheap phones for sale'), 
    ('house furniture for sale') 
; 

CREATE TABLE iterator (`index` int); 

INSERT INTO iterator 
    (`index`) 
VALUES 
    (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13),(14),(15), 
    (16),(17),(18),(19),(20),(21),(22),(23),(24),(25),(26),(27),(28),(29),(30) 
; 

Die zweite Tabelle enthält iterator must Zahlen von 1 bis N, wobei N größer oder gleich der Länge der längsten Zeichenkette in text.

Dann führen Sie diese Abfrage:

select 
    words.word, count(*) as `count` 
from 
(select 
    substring(concat(' ', t.title, ' '), i.index+1, j.index-i.index) as word 
from 
    text as t, iterator as i, iterator as j 
where 
    substring(concat(' ', t.title), i.index, 1) = ' ' 
and substring(concat(t.title, ' '), j.index, 1) = ' ' 
and i.index < j.index 
) AS words 
where 
    length(words.word) > 0 
and words.word not like '% %' 
group by words.word 
order by `count` desc, words.word asc 

Es gibt zwei wählt. Der äußere gruppiert und zählt einfach einzelne Wörter (Wörter mit einer Länge größer als 0 und ohne Leerzeichen). Inneres extrahiert alle Zeichenfolgen beginnend mit einem beliebigen Leerzeichen und endet mit einem beliebigen anderen Leerzeichen, so dass Zeichenfolgen keine Wörter sind (obwohl diese Unterabfrage words genannt wird), da sie andere Leerzeichen enthalten können als das Starten und Beenden von eins.

Ergebnisse:

word count 
for  6 
sale 6 
and  2 
cheap 2 
house 2 
androids 1 
cars 1 
cats 1 
dogs 1 
furniture 1 
iphones  1 
phones 1 
3

Sie ExtractValue in einige interessante Art und Weise nutzen können. SQL Geige Siehe hier: http://sqlfiddle.com/#!9/0b0a0/45

Wir brauchen nur eine Tabelle:

CREATE TABLE text (`title` varchar(29)); 

INSERT INTO text (`title`) 
VALUES 
    ('cheap cars for sale'), 
    ('house for sale'), 
    ('cats and dogs for sale'), 
    ('iphones and androids for sale'), 
    ('cheap phones for sale'), 
    ('house furniture for sale') 
; 

wir nun Reihe von wählt konstruieren, die ganze Wörter aus einem Text in XML konvertiert extrahieren. Jede Auswahl extrahiert das N-te Wort aus dem Text.

select words.word, count(*) as `count` from 
(select ExtractValue(CONCAT('<w>', REPLACE(title, ' ', '</w><w>'), '</w>'), '//w[1]') as word from `text` 
union all 
select ExtractValue(CONCAT('<w>', REPLACE(title, ' ', '</w><w>'), '</w>'), '//w[2]') from `text` 
union all 
select ExtractValue(CONCAT('<w>', REPLACE(title, ' ', '</w><w>'), '</w>'), '//w[3]') from `text` 
union all 
select ExtractValue(CONCAT('<w>', REPLACE(title, ' ', '</w><w>'), '</w>'), '//w[4]') from `text` 
union all 
select ExtractValue(CONCAT('<w>', REPLACE(title, ' ', '</w><w>'), '</w>'), '//w[5]') from `text`) as words 
where length(words.word) > 0 
group by words.word 
order by `count` desc, words.word asc 
Verwandte Themen