![]() |
![]() ![]() |
![]() |
![]()
Post
#1
|
|
Grupa: Zarejestrowani Postów: 5 Pomógł: 0 Dołączył: 17.05.2011 Ostrzeżenie: (0%) ![]() ![]() |
Witam serdecznie,
Tworzę właśnie system do wyszukiwania artykułów i mam problem z napisaniem odpowiedniego, wydajnego zapytania pobierającego dane. Myślę, że rozwiązanie tego mogłoby przydać się również innym użytkownikom forum. Do wyszukiwania artykułów wykorzystywana jest tabela wyszukiwanie o następujących kolumnach: id | id_artykulu | element | slowo | waga Do każdego artykułu przypisane są frazy kluczowe, nazwa oraz treść i w takiej kolejności są dla nas ważne przy wyszukiwaniu. Każdy z tych elementów podzielony jest na pojedyncze słowa. Aby dany artykuł mógł zostać wyświetlony powinniśmy znaleźć wszystkie wyszukiwane słowa w danym elemencie, przy czym każde znalezione słowo otrzymuje punktację wagową. Np. wyszukiwana fraza "piękna zima" otrzyma 2 000 000 pkt. wyszukana wśród fraz kluczowych, 20 000 w nazwie, 200 w treści. Wartości te nie sumują się w razie znalezienia w kilku elementach. Jeśli znajdziemy we frazie kluczowej to dalsze elementy nas nie interesują - tylko jeden, najwyżej oceniany element. Artykuł w tabeli wyszukiwania może więc wyglądać następująco (dwie frazy kluczowe, nazwa, treść): id | id_artykulu | element | slowo | waga ------------------------------------------------------ 1 | 1 | 1 | piękna | 1000000 1 | 1 | 1 | zima | 1000000 1 | 1 | 2 | ładne | 1000000 1 | 1 | 2 | lato | 1000000 1 | 1 | 3 | jakaś | 10000 1 | 1 | 3 | nazwa | 10000 1 | 1 | 4 | tresc | 100 1 | 1 | 4 | tego | 100 1 | 1 | 4 | artykulu | 100 Dane do wyświetlenia pobieramy z tabeli artykuly o następujących kolumnach: id | nazwa | tresc | waga_dodatkowa | top | aktywny Waga dodatkowa powinna być dodawana do obliczonej wagi w znalezionym elemencie. Jeśli artykuł ma 1 w kolumnie "top" to powinien być pozycjonowany wg wag na samej górze. Potem wyświetlamy artykuły o top = 0. Oczywiście bierzemy również pod uwagę kolumnę "aktywny". Teraz pytanie: jak napisać najbardziej optymalne zapytanie pobierające artykuły (powiedzmy 10 z danego przedziału) jak i również ilość wszystkich znalezionych artykułów (na potrzeby dzielenia na strony)? Próbowałem wstępnie pobrać aby samą listę artykułów, jednak otrzymują zdublowane wyniki, tzn. jeśli coś zostało znalezione w jednym artykule w 2 miejscach to otrzymuję to dwa razy. Zapytanie, które wykonuję:
Działa to jednak tylko w przypadku, gdy w kolumnie "element" znajdują się unikalne wartości dla każdego elementu, tak więc musiałbym tam mieć np. "1_1" itd. gdzie pierwsza liczba to id artykułu. Pozdrawiam serdecznie i dziękuję z góry za pomoc. EDIT ----------------------------- Dodam jeszcze, że ilość rekordów może być liczona nawet w milionach tak więc fajnie, gdyby było to dość wydajne rozwiązanie ![]() Ten post edytował adam_c 28.12.2011, 18:09:59 |
|
|
![]()
Post
#2
|
|
![]() Grupa: Zarejestrowani Postów: 1 333 Pomógł: 137 Dołączył: 25.03.2008 Skąd: jesteś?? Ostrzeżenie: (0%) ![]() ![]() |
Szczerze to nie zajmuję się wyszukiwaniem i niczego oprócz pełno tekstowego nie używałem, ale to co proponujesz wydaje mi się przekombinowane.
Co na pewno jest do zmiany to pole |waga| podmień je na |idWaga| i stwórz tabelę z wagami |id|title|waga|. Cały kod rozumiem działa tak, że podczas dodawania nowego arta rozwalasz każdą jego część na słowa i dodajesz je do tej tabeli - jej rozmiary będą ogromne, nie wiem jak z prędkością tej metody, ale strata powierzchni występuje na pewno, a edycja arta lub czegokolwiek innego spowoduje sporo pracy nad tą tabelą. (Zakładając, że arty mają komentarze które też w taki sposób traktujesz to już w ogóle). Pomyślał bym nad przerobieniem tego, nie wiem jak z słowami kluczowymi (tagami), tytułami - może Twój sposób i jest optymalny, ale przy treści skorzystał bym z wyszukiwania pełnotekstowego - nie sądzisz, że to lepszy sposób? -------------------- Mój blog - o wszystkim i niczym ale zazwyczaj związane z informatyką! ;-)
Githube Usługi spawalnicze i monterskie | Park linowy Lublin i Okunince |
|
|
![]()
Post
#3
|
|
Grupa: Zarejestrowani Postów: 5 Pomógł: 0 Dołączył: 17.05.2011 Ostrzeżenie: (0%) ![]() ![]() |
Nie chciałem aż tak mieszać na forum więc uprościłem nieco metodę. U mnie działałoby to tak, że artykuł dzielę na słowa, każde słowo sprowadzam do podstawowej formy, a następnie wrzucam do tablicy globalnej ze słowami, jeśli jeszcze go tam nie ma. Każde słowo ma przypisane ID i właśnie to ID jest zapisywane w tabeli wyszukiwania. Fraza wpisana do wyszukiwarki również zostaje podzielona na słowa i sprowadzona do podstawowej formy. W tym momencie bardzo łatwo znaleźć w tabeli słowa, których szukamy bez potrzeby sprawdzania każdego artykułu po kolei. Wiemy także, czy w ogóle takie słowo istnieje w serwisie, sprawdzając to w tabeli ze słowami zaindeksowanymi. Czy lepiej byłoby jednak nie rozdzielać tego w tabeli wyszukiwania i użyć fulltext search?
|
|
|
![]()
Post
#4
|
|
![]() Grupa: Zarejestrowani Postów: 175 Pomógł: 18 Dołączył: 11.06.2007 Skąd: Koszalin/Poznań Ostrzeżenie: (0%) ![]() ![]() |
Na obecnym etapie rozwoju i łatwości implementacji silników wyszukiwania takich jak apache solr/sphinx/xapian moim zdaniem budowanie większych wyszukiwarek w bazie danych nie ma najmniejszego sensu.
|
|
|
![]()
Post
#5
|
|
![]() Grupa: Zarejestrowani Postów: 1 333 Pomógł: 137 Dołączył: 25.03.2008 Skąd: jesteś?? Ostrzeżenie: (0%) ![]() ![]() |
Wszystko to działa na serwerze, a co jeśli nie mamy dedyka?
@adam_c wybacz, że się w trącam, ciekaw jestem tego tematu, a jeśli uda się coś znaleźć przy okazji będziesz mieć łatwiej. :-) -------------------- Mój blog - o wszystkim i niczym ale zazwyczaj związane z informatyką! ;-)
Githube Usługi spawalnicze i monterskie | Park linowy Lublin i Okunince |
|
|
![]()
Post
#6
|
|
Grupa: Zarejestrowani Postów: 5 Pomógł: 0 Dołączył: 17.05.2011 Ostrzeżenie: (0%) ![]() ![]() |
Witam,
Dzięki za odpowiedzi ![]() Skrypt będzie działał na hostingu współdzielonym, tak więc mam ograniczone możliwości. Zaktualizowałem nieco bazę i zapytanie i jest prawie dobrze. W tej chwili tabele bazy wyglądają tak: Tabela "artykuly": id | nazwa | tresc | dodatkowa_waga | top | aktywny Tabela "search_indeksy": id | slowo Tabela "search_rodzaje_elementow": id | nazwa | waga Tabela "search_wyszukiwanie": id | id_matki | numer_elementu | rodzaj_elementu | indeks Samo zapytanie brzmi tak (pomijam wyszukiwanie indeksów, wcześniej pobrałem je do tablicy $wyszukiwane):
Wszystko byłoby super, gdyby nie pierwsza część czyli DISTINCT(t2.id). Wydawało mi się, że powinno to działać tak, że nie pobierze mi np. artykułu 1, a tak się nie dzieje, a raczej dzieje się ale nie do końca. Powiedzmy, że znaleziono wyszukiwane słowa w dwóch tagach artykułu 1 oraz w jego nazwie. Logiczne byłoby pozostawienie wyszukania z taga (wyższa waga), pominięcie drugiego oraz tego z nazwy. W praktyce jednak drugi wyszukany element (drugi tag) zostaje pominięty, jednak element wyszukany po nazwie pozostaje. Wygląda na to, że zapytanie odrzuciło drugi wyszukany element po tagu, bo był całkowicie identyczny, a w trzecim zmieniła się waga (nazwa ma mniejszą) więc jest już coś innego i nie wywala go. Nieco namieszałem ale mam nadzieję, że wiadomo o co chodzi. Jak to rozwiązać? Macie pomysły? ![]() EDIT ------------------------ Witam ponownie, Udało mi się napisać odpowiednie zapytanie. Nie jest może ono za krótkie, ale zdaje egzamin i pobiera co trzeba:
Co o tym sądzicie? Nie wspomniałem wcześniej, że "numer_elementu" w tabeli "wyszukiwanie" składa się z id_matki i kolejnego numeru elementu (np. 1_1 dla pierwszego taga artykułu 1). Teraz wystarczy tylko LIMIT i można dzielić na strony. Czy pobranie ilości wszystkich znalezionych artykułów drugim zapytaniem z COUNT ale bez ORDER będzie najbardziej odpowiednie, czy jest jakieś lepsze rozwiązanie? Pozdrawiam Ten post edytował adam_c 29.12.2011, 10:21:45 |
|
|
![]() ![]() |
![]() |
Wersja Lo-Fi | Aktualny czas: 21.06.2025 - 08:26 |