Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

> wyszukiwanie - problem z zapytaniem
qchar
post 30.12.2009, 17:44:30
Post #1





Grupa: Zarejestrowani
Postów: 24
Pomógł: 0
Dołączył: 19.07.2007

Ostrzeżenie: (0%)
-----


Witam

Mam dużą bazę danych ze zdjęciami, i słowami kluczowymi. W uproszczeniu baza składa się z 2 tabel: zdjęcia z polami id_zdjecia i ścieżką do zdjęcia oraz tabelę słowa kluczowe, gdzie mam pola id, id_zdjecia, slowo. I teraz chciałbym jednym zapytaniem sql znaleźć zdjęcia które mają przypisane np 2 słowa kluczowe np: jeśli wpiszę "piłka nożna", chcę znaleźć tylko te identyfikatory zdjęć które mają słowo PIŁKA i NOŻNA. Wszelkie moje próby kończą się 2 wyjściami. Albo dostaję wynik w postaci identyfikatorów zdjęć zawierających słowo piłka lub słowo nożna, albo pusty zbiór danych. Oczywiście mam w bazie słów kluczowych takie wpisy, gdzie do jednego identyfikatora zdjęcia przypisane są oba te słowa. Robię to mniejwiecej tak:
OPCJA 1:
  1. SELECT DISTINCT img_id FROM keywords WHERE word LIKE "PILKA%" OR word LIKE "NOZNA%"

OPCJA 2:
  1. SELECT DISTINCT img_id FROM keywords WHERE word LIKE "PILKA%" AND word LIKE "NOZNA%"


Proszę o jakąś podpowiedź, bo stanąłem w miejscu, w którym nie spodziewałem się w ogóle problemu...
Go to the top of the page
+Quote Post
2 Stron V   1 2 >  
Start new topic
Odpowiedzi (1 - 19)
Mchl
post 30.12.2009, 19:11:45
Post #2





Grupa: Zarejestrowani
Postów: 855
Pomógł: 145
Dołączył: 17.07.2008
Skąd: High Memory Area

Ostrzeżenie: (0%)
-----


WHERE word LIKE '%PILKA%' OR word LIKE '%NOZNA%'
Go to the top of the page
+Quote Post
qchar
post 30.12.2009, 20:19:34
Post #3





Grupa: Zarejestrowani
Postów: 24
Pomógł: 0
Dołączył: 19.07.2007

Ostrzeżenie: (0%)
-----


Nie wiem, może nie byłem za bardzo precyzyjny, ale takie zapytanie zwraca mi tak jak napisałem wszystkie zdjęcia powiązane ze słowem PIŁKA oraz te ze słowem NOŻNA konkretnie rzecz ujmując ~ok 35000 rekordów. A ja chciałbym dostać TYLKO te zdjęcia które opisane są oboma słowami, których w bazie mam mniejwięcej 12000.
Go to the top of the page
+Quote Post
Mchl
post 30.12.2009, 20:44:31
Post #4





Grupa: Zarejestrowani
Postów: 855
Pomógł: 145
Dołączył: 17.07.2008
Skąd: High Memory Area

Ostrzeżenie: (0%)
-----


No to w takim razie:

WHERE word LIKE '%PILKA%' AND word LIKE '%NOZNA%'
Go to the top of the page
+Quote Post
qchar
post 30.12.2009, 23:04:26
Post #5





Grupa: Zarejestrowani
Postów: 24
Pomógł: 0
Dołączył: 19.07.2007

Ostrzeżenie: (0%)
-----


No dobra, ale jak popatrzysz na mój pierwszy post OBA rozwiązania które proponujesz są w tam i oba zapytania nie działają, przynajmniej nie tak jak bym tego oczekiwał. Dlatego właśnie piszę na forum...
Go to the top of the page
+Quote Post
Mchl
post 31.12.2009, 00:01:13
Post #6





Grupa: Zarejestrowani
Postów: 855
Pomógł: 145
Dołączył: 17.07.2008
Skąd: High Memory Area

Ostrzeżenie: (0%)
-----


Ale jak popatrzyzs na moje propozycje, to zauważysz że różnią się od twoich małymi, ale istotnymi detalami (dosłownie dwoma)
Go to the top of the page
+Quote Post
qchar
post 31.12.2009, 01:50:39
Post #7





Grupa: Zarejestrowani
Postów: 24
Pomógł: 0
Dołączył: 19.07.2007

Ostrzeżenie: (0%)
-----


Twoja propozycja nie działa, bo jest praktycznie identyczna jak moja. Co do różnic, widzę 2, moim zdaniem nie istotne dla istoty problemu: ja mam cudzysłowy, ty ', ja mam jeden znak procenta po wyrazie który szukam(bo tak własnie chce szukać - to co wpiszę+jakieś znaki, stąd WYRAZ%), Ty proponujesz % także przed wyrazem, mi zupełnie niepotrzebne(bo to oznaczało by szukania fraz jakiesZnakiWYRAZjakiesZnaki). Dodam dla uściślenia że w polu word zawsze znajduje się jedno słowo, więc prawdę mówiąc można by szukać bez procentów, lub w ogóle pisząc word = "SZUKANYWYRAZ". Ale żeby nie było - sprawdziłem mimo wszystko. Więc stwierdzam raz jeszcze - nie działa. W obrazku zrzut ekranu:

Jeśli czegoś więcej nie widzę, proszę o oświecenie, bo mija już drugi dzień jak z tym walczę a rozwiązania łopatologiczne jakie stosuje są niedopuszczalnie wolne.
Go to the top of the page
+Quote Post
Mchl
post 31.12.2009, 08:47:55
Post #8





Grupa: Zarejestrowani
Postów: 855
Pomógł: 145
Dołączył: 17.07.2008
Skąd: High Memory Area

Ostrzeżenie: (0%)
-----


No to trzeba było zacząć od opisania struktury danych. Zasugerowałem się Twoimi zapytaniami, że trzymasz wszystkie słowa kluczowe w jednym polu. (W sumie moja wina, bo z Twojego pierwszego posta wynika co innego)

Ok.

Spróbuj tak:

Kod
SELECT fl_kw_img_id AS c, GROUP_CONCAT(fl_kw_word) AS w FROM keywords GROUP BY fl_kw_img_id HAVING w LIKE '%STADION%' AND w LIKE '%WARSZAWA%'


Ten post edytował Mchl 31.12.2009, 08:49:40
Go to the top of the page
+Quote Post
qchar
post 31.12.2009, 12:04:10
Post #9





Grupa: Zarejestrowani
Postów: 24
Pomógł: 0
Dołączył: 19.07.2007

Ostrzeżenie: (0%)
-----


smile.gif No właśnie taką mam strukturę narzuconą, i raczej muszę przy niej pozostać, choć sam pewnie bym to trochę inaczej zorganizował. Cieszę się, że w końcu widzę że można to zrobić jednym zapytaniem. Tylko pozostał mi problem szybkości. Bo pisząc w ten sposób jak proponujesz czekam na wynik 30s. Do tej pory, ponieważ, nie potrafiłem napisać tego jedną linijką (bo spodziewałem się że będzie szybciej) radziłem sobie w taki sposób, że pobierałem wszystkie id zdjęć zawierające jedno słowo, wszystkie id zawierające słowo, i dalej już za pomocą PHP w otrzymanych tablicach wybierałem te zawierające oba. I taki sposób trwa nie uwzględniając cache mysql-a ok 15 sekund. Ale mimo wszystko jestem wdzięczny bardzo bo myślę że mam punkt wyjścia jakiś do dalszych rozważań, szczególnie że niewiele mam tylko kilka takich słów których jest w bazie tak dużo że powodują problem. I w końcu jakieś życiowe zastosowanie funkcji GROUP_CONCAT o której też myślałem. winksmiley.jpg Jeszcze raz dzięki.
Go to the top of the page
+Quote Post
Mchl
post 31.12.2009, 12:32:53
Post #10





Grupa: Zarejestrowani
Postów: 855
Pomógł: 145
Dołączył: 17.07.2008
Skąd: High Memory Area

Ostrzeżenie: (0%)
-----


Inny sposób, być może szybszy, może wyglądać tak:

Kod
SELECT t1.fl_kw_img_id AS c FROM keywords AS t1 CROSS JOIN keywords AS t2 USING (fl_kw_img_id) WHERE t1.fl_kw_word = 'STADION' AND t2.fl_kw_word = 'WARSZAWA'

Problem z tym jest taki, że dla dwóch, czy trzech słow to będzie jeszcze jako tako, ale potem coraz bardziej się ślimaczy (bo trzeba kolejne JOINy dorzucać)
Go to the top of the page
+Quote Post
qchar
post 31.12.2009, 13:02:06
Post #11





Grupa: Zarejestrowani
Postów: 24
Pomógł: 0
Dołączył: 19.07.2007

Ostrzeżenie: (0%)
-----


O to jest świetne! Wielkie dzięki!
Go to the top of the page
+Quote Post
Mchl
post 31.12.2009, 13:13:30
Post #12





Grupa: Zarejestrowani
Postów: 855
Pomógł: 145
Dołączył: 17.07.2008
Skąd: High Memory Area

Ostrzeżenie: (0%)
-----


Dla formalności zapytam: indeksy w tej tabeli masz? Jakie?
Go to the top of the page
+Quote Post
qchar
post 31.12.2009, 14:34:52
Post #13





Grupa: Zarejestrowani
Postów: 24
Pomógł: 0
Dołączył: 19.07.2007

Ostrzeżenie: (0%)
-----


Mam, mam. Tak to mniejwięcej wygląda
  1. CREATE TABLE IF NOT EXISTS `keywords` (
  2. `fl_kw_id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
  3. `fl_kw_img_id` bigint(20) UNSIGNED NOT NULL,
  4. `fl_kw_word` varchar(50) COLLATE utf8_polish_ci NOT NULL,
  5. PRIMARY KEY (`fl_kw_id`),
  6. KEY `fl_kw_img_id` (`fl_kw_img_id`),
  7. KEY `fl_kw_word` (`fl_kw_word`)
  8. ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_polish_ci;
Go to the top of the page
+Quote Post
Mchl
post 31.12.2009, 17:45:16
Post #14





Grupa: Zarejestrowani
Postów: 855
Pomógł: 145
Dołączył: 17.07.2008
Skąd: High Memory Area

Ostrzeżenie: (0%)
-----


Kod
ALTER TABLE keywords
  ADD INDEX imgID_word(fl_kw_img_id,fl_kw_word)


(na dobrą sprawę, to mógłby być Twój PRIMARY)

Sprawdź EXPLAINem, ale wydaje mi się, że powinien dobrze pasować do tego zapytania.
Go to the top of the page
+Quote Post
qchar
post 3.01.2010, 00:13:20
Post #15





Grupa: Zarejestrowani
Postów: 24
Pomógł: 0
Dołączył: 19.07.2007

Ostrzeżenie: (0%)
-----


A to nie jest tak, że polo PRIMARY KEY musi być unikalne? Bo u mnie w tej tabeli tak nie jest stąd podejrzewam oddzielne pole z indeksem. Ale nawet w takiej strukturze to ostatnie zapytanie nieźle dawało radę, mimo że wiele czasu na testy nie miałem przed sylwkiem, więc pewnie będe z niego intensywnie korzystał.
Go to the top of the page
+Quote Post
Mchl
post 3.01.2010, 00:16:51
Post #16





Grupa: Zarejestrowani
Postów: 855
Pomógł: 145
Dołączył: 17.07.2008
Skąd: High Memory Area

Ostrzeżenie: (0%)
-----


Musi być, ale podejrzewam, że nie masz dwa razy tego samego słowa przypisanego do jednego obrazka.
Go to the top of the page
+Quote Post
qchar
post 3.01.2010, 14:46:07
Post #17





Grupa: Zarejestrowani
Postów: 24
Pomógł: 0
Dołączył: 19.07.2007

Ostrzeżenie: (0%)
-----


No właśnie niestety mam, bo ktoś tworząc tą całą bazę poszedł w wielu miejscach na skróty. Dlatego też pewnie w miarę czasu będę szukał sposobu żeby te duplikaty łatwo szybko i przyjemnie usunąć.
Go to the top of the page
+Quote Post
Mchl
post 3.01.2010, 18:47:20
Post #18





Grupa: Zarejestrowani
Postów: 855
Pomógł: 145
Dołączył: 17.07.2008
Skąd: High Memory Area

Ostrzeżenie: (0%)
-----


UWAGA: Nie sprawdzone. Nie biorę gwarancji. Nie testować na żywych danych.

To powinno załatwić sprawę duplikatów

Kod
DELETE
  FROM keywords
  WHERE fl_kw_id IN (
    SELECT DISTINCT t1.fl_kw_id
    FROM keywords AS t1
    CROSS JOIN keywords AS t2
    USING(fl_kw_img_id,fl_kw_word)
    WHERE t1.fl_kw_id > t2.fl_kw_id
  )


Ten post edytował Mchl 3.01.2010, 18:47:35
Go to the top of the page
+Quote Post
qchar
post 3.01.2010, 19:25:43
Post #19





Grupa: Zarejestrowani
Postów: 24
Pomógł: 0
Dołączył: 19.07.2007

Ostrzeżenie: (0%)
-----


Wywała błąd:
#1093 - You can't specify target table 'keywords' for update in FROM clause

Z braku czasu nie googlowałem za dużo, ale nie wiem czy nie trafiliśmy na jakiś bug w mysql...
Go to the top of the page
+Quote Post
Mchl
post 3.01.2010, 19:57:59
Post #20





Grupa: Zarejestrowani
Postów: 855
Pomógł: 145
Dołączył: 17.07.2008
Skąd: High Memory Area

Ostrzeżenie: (0%)
-----


Nie nie... to ma sens...
Spróbuj tego:

Kod
DELETE
  k
  FROM
  keywords AS k,
  (
    SELECT DISTINCT t1.fl_kw_id
    FROM keywords AS t1
    CROSS JOIN keywords AS t2
    USING(fl_kw_img_id,fl_kw_word)
    WHERE t1.fl_kw_id > t2.fl_kw_id
  ) AS sq
  WHERE k.fl_kw_id = sq.fl_kw_id
Go to the top of the page
+Quote Post

2 Stron V   1 2 >
Reply to this topicStart new topic
1 Użytkowników czyta ten temat (1 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Wersja Lo-Fi Aktualny czas: 14.08.2025 - 07:32