Oprogramowanie do sklepu internetowego – które wybrać?

To że przyszłość zakupów jest w internecie, tego tłumaczyć nikomu raczej nie trzeba, co rusz powstają nowe sklepy internetowe… chodzą też słuchy, że w e-commerce podobno są pieniądze… skoro tak to i ja zapragnąłem spróbować.

Jakiś czas temu stanąłem zatem przed decyzją wyboru platformy e-commerce dla sklepu internetowego. Na rynku dostępnych jest wiele różnych platform lub produktów box’owych, niestety wcale nie znaczy, że jest z czego wybierać.

Poniżej garść informacji, kilka porad i linków dla osób planujących założenie własnego sklepu w necie. Mam nadzieję, że komuś się przyda. Czytaj dalej „Oprogramowanie do sklepu internetowego – które wybrać?”

Numerowanie listy zwracanych rekordów w MySQL

Przy różnorakich konkursach często zachodzi potrzeba wyciągnięcia pozycji konkretnego użytkownika (wpisu w bazie) na tle innych użytkowników (wpisów) w ograniczeniu czasowym.

Czyli np. mamy 10 tys wyników gry z danego dnia i chcemy poznać pozycje w rankingu, które zajmują użytkownicy o identyfikatorach 1, 2, 3.

Oczywistym rozwiązaniem jest zwykły selekt z ORDER BY po polu z punktami i następnie iterowanie w php, jednak gdy liczba danych będzie większa taki SELECT nie wykona się lub będzie bardzo niewydajny.

Rozwiązaniem dużo lepszym jest użycie podzapytania i wykonania obliczeń numerowania na samej bazie a następnie zwrócenie do php jedynie rekordów pasujących do naszych użytkowników. Czytaj dalej „Numerowanie listy zwracanych rekordów w MySQL”

Jak promować serwis na Facebook’u?

Tego, że w dzisiejszych czasach obecność Twojego serwisu lub marki na Facebook’u jest niezbędna, tłumaczyć chyba nie trzeba. Jeżeli Cię tam nie ma – tracisz, gdyż Twoja konkurencja już tam jest i czerpie z tego profity.

Okej, zatem mając serwis internetowy (aka marka/firma) i konto na fejsie, jak mogę czerpać tego korzyści? Czytaj dalej „Jak promować serwis na Facebook’u?”

Sphinx, czyli szybkie i skuteczne wyszukiwanie

Sphinx to open source’owy silnik wyszukiwarki SQL. Sphinx jest dostępny na licencji GPL 2 i jest całkowicie darmowy do zastosowań webowych.

Sphinx został stworzony przez rosyjskich programistów, aplikacja jest cały czas rozbudowywana i rozwijana, posiada płatny support.

Zasada działania Sphinxa

Sphinx jest aplikacją stand-alone, musi zostać skompilowany i zainstalowany na serwerze. Działa na zadadzie deamon-client.

Sphinx składa się z kilku narzędzi:

  • searchd – deamon wyszukiwarki. Musi być cały czas uruchomiony, na podstawie parametrów wywołania oraz konfiguracji przeszukuje indeksy i zwraca rezultaty.
  • indexer – generator indeksu. Służy do budowania indeksu, po którym następuje wyszukiwanie.
  • search – narzędzie pozwalają testować wyszukiwarkę z poziomu linii komend.
  • spelldump – narzędzie pomocne przy budowania słownika
  • indextool – narzędzie wprowadzone dopiero w wersji 0.9.9-rc2. Służy do debugowania i wyświetlania informacji o zbudowanym indeksie.

Cechy Sphinxa

  • Ekstremalnie szybkie indeksowanie (aż do 10MB/sec).
  • Ekstremalnie szybkie wyszukiwanie (około 0.1 sekundy dla 2-4 GB zbiorów danych).
  • Bardzo duża skalowalność (aż do 100 GB zbiorów danych na pojedyńczym CPU).
  • Współpracuje z wieloma typami baz danych: PostgreSQL, MySQL i MSSQL.
  • Posiada API dla języków takich jak PHP, Python, Java, Perl, Ruby i C/C++.
  • Obsługuję morfologię (przeszukiwanie pełnotekstowe (brak języka polskiego)).
  • Umożliwia sortowanie/filtrowanie wyników po zadanych atrybutach.
  • Umożliwia grupowanie rezultatów po zadanym atrybucie.
  • Wspiera stronnicowanie rezultatów.
  • Prosty, a zarazem dostarczający wiele możliwści plik konfiguracyjny.

Sphinx nie operuje bezpośrednio na bazie danych a jedynie na wcześniej przygotowanych indeksach. Dzięki temu zdejmujemy obciążenie z „wąskiego gardła”, którym w praktycznie każdej aplikacji jest baza danych i przeżucamy na serwer.

Wady Sphinxa

Jedyną znaną mi wadą Sphinxa jest to, że wcześniej stworzony indeks (po którym odbywa się wyszukiwanie) nie jest automatycznie aktualizowany o zmiany wykonane na bazie danych. Dotyczy to zarówno nowych wierszy w zaindeksowanej tabeli jak i modyfikacji zaindeksowanych już danych.

Nowe/zmienione dane pojawią się w indeksie dopiero po jego zaktualizowaniu poprzez polecenie:

indexer nazwa_indeksu --rotate

Pomimo dużej szybkości indexera, operację tą nie nie można wykonywać po każdej zmianie w bazie danych a jednie cyklicznie co kilka godzin/dni (w zależności od wielkości indeksu).

O ile brak aktualizacji indeksu o zmodyfikowane rekordy nie stanowi większego problemu, to brak nowych rekordów może stanowić dla wielu serwisów poważny problem. Często bywa tak, że użytkownicy wprowadzają jakieś dane do bazy a następnie chcą ich użyć wyszukując je. Rozwiązaniem jest mechanizm Live index updates.

W skrócie działa to następująco:

  • Na indeksowanej tabeli tworzymy 2 indexy: główny (main) i dodatkowy (delta).
  • Tworzymy tabelę sph_counter, w której będziemy zapisywać max(id) z indeksu głównego.
  • Indeks główny będzie wyszukiwał w 99,9% danych indeksowanej tabeli, indeks dodatkowy będzie wyszukiwał w 0.1% danych tabeli.
  • Dzięki rozbiciu indeksowania na 2 indeksy (duży główny, mały dodatkowy) możliwe jest dużo częstsze indeksowanie indeksu dodatkowego gdyż będzie zawierał on niewiele danych, zatem reindeksacja nie będzie obciążać serwera i bazy danych.
  • Modyfikujemy sphinx.conf wg. wytycznych z linka.
  • Ustawiamy w cronie reindeksowanie głównego indeksu „raz na dzień” oraz dodatkowego indeksu np. „co 3 minuty”.
  • Zatem, co 3 minuty będziemy uzupełniać indeks dodatkowy, natomiast raz dziennie będzie uzupełniany indeks główny.
  • Każdorazowo przy aktualizacji indeksu głównego do tabeli sph_counter zostanie zapisany wartość klucza głównego (sql_query_pre), przez co indeks pomocniczy będzie startował od zera.

Zasada działania aplikacji opartej na Sphinx’ie

  • Skonfigurowanie konfiga „sphinx.conf” i zbudowanie indeksów.
  • W aplikacji, poprzez api następuje wywołanie Sphinxa z parametrami (szukana fraza, limit, offset, order etc…).
  • Sphinx zwraca wyszukane rekordy w postaci tablicy kluczy głównych (+ zdefiniowane atrybuty).
  • Na podstawie ID’ków kluczy głównych wyciągamy dane z bazy (lub z cache’a) i prezentujemy w serwisie.

Szybki tutorial

  • Tworzymy i konfigurujemy plik konfiguracyjny sphinx.conf.
  • Bujemy indeks(y)
    indexer --all
    
  • Odpalamy demona:
    /usr/local/bin/searchd -c /usr/local/etc/sphinx.conf
    
  • Testujemy wyszukiwanie po indeksie:
    search [INDEX_NAME] SZUKANA_FRAZA
    
  • Podpinamy API
  • Testujemy wyszukiwanie poprzez API

Błąd „connection to 127.0.0.1:9312 failed (errno=111 ….”

W przypadku gdy najpierw został uruchomiony deamon Sphinxa a dopiero później stworzony indeks to aby API działało poprawnie należy zrestartować demona. To samo tyczy się przypadku gdy w indeksie sphinx.conf zostały zmienione zwracane atrybuty.

/usr/local/bin/searchd --stop
/usr/local/bin/searchd -c /usr/local/etc/sphinx.conf

Błąd „błąd „searchd error: offset out of bounds””

W przypadku gdy chcemy zwiększyć domyślną liczbę zwracanych (przetwarzanych) rekordów z 1000 na więcej należy:

  • zmienić max_matches w sekcji searchd w konfigu sphinx.conf,
  • zrestartować demona searchd,
  • ustawić 3 parametr w metodzie SetLimits().

Z Sphinx’a korzystają między innym: craigslist.org, filestube.com, netlog.com, thepiratebay.org, wikimapia.org i wiele więcej.

Niedługo, jak czas pozwoli, postaram się jeszcze napisać coś o samym pliku konfiguracyjnym Sphinxa „sphinx.conf”.

Zaosoby Amazon S3 we własnej domenie

O samym Amazon S3 nie będę się rozwodził gdyż już nie raz pisałem o tej usłudze. Generalnie jest to bardzo wydajna usługa hostingu plików w chmurze amazona.

Problem

Standardowe URLe prowadzące do zasobów zgromadzonych na serwerach europejskich wyglądają następująco:

http://UNIQUE-BUCKET-NAME.s3-external-3.amazonaws.com/katalog/plik.jpg

Gdzie UNIQUE-BUCKET-NAME to unikalna w skali globalnej nazwa nadawana przez dewelopera.

Powyższy adres jest bardzo długi i nie wygląda zbyt przyjaźnie. Jeżeli komuś zależy na pewnych walorach estetycznych to pewnie wolałby zmienić ten adres na:

http://subdomena.domena.pl/katalog/plik.jpg

Rozwiązanie

Posłużę się przykładem, gdyż taki przekaz będzie najprostszy i najlepiej rozumiany. Załóżmy, że posiadamy domenę lorem.pl, wszystkie statyczne pliki hostujemy na Amazon i chcemy je widzieć pod subdomeną static.lorem.pl.

W Amazon S3 tworzymy bucket (jeżeli już mamy utworzony to zmieniamy nazwę) o nazwie identycznej do subdomeny czyli static.lorem.pl.

Następnie tworzymy rekord CNAME dla subdomeny static.lorem.pl i ustawiamy go na „s3-external-3.amazonaws.com.” (tak, musi być kropka na końcu). Rekord CNAME można ustawić w panelu administracyjnym dostarczonym przez firmę hostingową, jeżeli nie posiadacie takiej opcji to musicie przesłać dyspozycję na support.

Koniec, zmiany nie będą widoczne od razu, należy poczekać godzinę, maksymalnie kilka godzin, pliki wgrane na Amazon powinny być widoczne z poziomu subdomeny. Należy też pamiętać, aby po wgraniu plików na Amazon ustawić plikom odpowiednie ACL (prawa dostępu). W CloudBerry: PPM na bucket->ACL->ACL Settings->Public->OK

UPDATE z ORDER BY w jednym zapytaniu na przykładzie orderingu danych

Wstęp

Mamy przykładową tabelę z userami:

DROP TABLE users;
CREATE TABLE users(
	id SERIAL PRIMARY KEY,
	name VARCHAR(50),
	created TIMESTAMP DEFAULT NOW()
);

INSERT INTO users(name) VALUES('Marcin');
INSERT INTO users(name) VALUES('Bartek');
INSERT INTO users(name) VALUES('Agnieszka');
INSERT INTO users(name) VALUES('Dominika');

Na tabeli wykonywane były wielokrotnie operacje INSERT/UPDATE/DELETE przykładowo:

UPDATE users SET name = 'Ania' WHERE name = 'Bartek';
UPDATE users SET name = 'Dalia' WHERE name = 'Marcin';
DELETE FROM users WHERE name = 'Ania';

Zatem SELECT bez orderu wyświetli nam dane posortowane względem kolejności modyfikacji:

SELECT * FROM users;

psql=> select * from users;
 id |   name    |          created
----+-----------+----------------------------
  3 | Agnieszka | 2009-12-19 10:41:49.324851
  4 | Dominika  | 2009-12-19 10:41:49.958792
  1 | Dalia     | 2009-12-19 10:41:49.297223
(3 rows)

W interface aplikacji chcemy oprogramować własną obsługę kolejności rekordów. Dodajemy zatem kolumnę, która będzie obsługiwać tą funkcjonalność.

ALTER TABLE users ADD COLUMN order_id INTEGER;

Problem

Musimy teraz uzupełnić kolumne order_id o poprawne wartości. Kolejność orderu danych, które znajdują się w bazie powinna być kolejności wprowadzania tych danych do tabeli (czyli zgodna z kolejnością pola id).

Aby zrealizować poprawne uzupełnienie orderu tworzymy pomocniczą sekwencję, która wykorzystamy do wygenerowania kolejnych liczb do orderu:

DROP SEQUENCE order_id_seq;
CREATE SEQUENCE order_id_seq;

Wykonujemy oczywiste zapytanie przypisujące rekordom z tabeli users kolejne wartości sekwencji:

UPDATE users SET order_id = NEXTVAL('order_id_seq');  

Niestety przez to, że dane nie były ustawione w dobrej kolejności ORDER ustawiony jest niepoprawnie.

psql=> SELECT * FROM users;
 id |   name    |          created           | order_id
----+-----------+----------------------------+----------
  3 | Agnieszka | 2009-12-19 10:41:49.324851 |        1
  4 | Dominika  | 2009-12-19 10:41:49.958792 |        2
  1 | Dalia     | 2009-12-19 10:41:49.297223 |        4
(3 rows)

Rozwiązanie

Aby UPDATE poprawnie ustawił kolejność orderu należy nieco zmodyfikować zapytanie i nadać danym z tabeli users odpowiednią kolejność.

W tym celu tworzymy podzapytanie sorted_ids, w którym poprzez ORDER BY ustalamy kolejność rekordów, które następnie w zapytaniu nadrzędnym zostaną zmodyfikowane właśnie w tej kolejności.

UPDATE users
	SET order_id = correct_order_id
FROM
	(
	SELECT 
		id, nextval('order_id_seq') as correct_order_id
	FROM
		users
  	ORDER BY 
		id ASC
	) as sorted_ids
WHERE
	users.id = sorted_ids.id; 

select * from users order by order_id;

Jak widać dane zostały pięknie zorderowane:

psql=> select * from users order by order_id;
 id |   name    |          created           | order_id
----+-----------+----------------------------+----------
  1 | Dalia     | 2009-12-19 10:41:49.297223 |        1
  3 | Agnieszka | 2009-12-19 10:41:49.324851 |        2
  4 | Dominika  | 2009-12-19 10:41:49.958792 |        3
(3 rows)

Przy okazji wspomnę, że w aplikacji łatwiej obsłużyć ordering odwrotny, tzn. wiersze, które posiadają największą wartość order_id są na czele a nie na końcu listy. Przy takim podejściu przy wstawianiu nowego rekordu pole order_id powinno mieć wartość MAX(order_id) + 1. Dla orderingu odwrotnego należy zmienić w podzapytaniu kolejność sortowania z id ASC na id DESC.

Należy także dbać o to, aby przy usunięciu rekordu prenumerować order_id wszystkich rekordów, które znajdują się 'nad nim’ o -1.

Startup LubimyCzytać.pl – społeczność czytelników!

LubimyCzytać.pl - społeczność czytelników Przez ostatnie miesiące zaangażowany byłem w autorski projekt LubimyCzytać.pl.

Po wielu zmaganiach z przeciwnościami losu i własnym lenistwem serwis ruszył pod koniec listopada. Muszę przyznać, że czas powstawania serwisu był dosyć długi a tworzenie serwisów takiej wielkości 'po godzinach’ w dwie osoby bez dodatkowego finansowania i wsparcia jest dosyć męczące.

Nie chcę teraz przynudzać o moich przemyśleniach związanych z powstawaniem i tworzeniem startupa, jeżeli jesteście zainteresowani kulisami oraz wnioskami płynącymi z tego doświadczenia, to proszę o info w komentarzach. Jak będzie zainteresowanie, to przeznaczę na to oddzielny wpis.

Czym jest LubimyCzytać.pl?

Głównym celem serwisu LubimyCzytać.pl jest umożliwienie wymiany informacji pomiędzy ludźmi, którzy lubią czytać książki. Poprzez opinie, recenzje i oceny przeczytanych książek użytkownicy mogą sobie nawzajem polecać książki warte uwagi.

Główną funkcjonalnością serwisu jest „wirtualna biblioteczka” czyli miejsce, w którym każdy czytelnik może składować książki które przeczytał, teraz czyta oraz chce przeczytać. W biblioteczce można tworzyć własne półki i zapełniać je książkami.

Na podstawie książek zgromadzonych w biblioteczce oraz ocen książek system proponuje spersonalizowaną listę książek, które powinny zaciekawić czytelnika. Z uwagi na aktualnie panujący bałagan w bazie danych książek funkcjonalność nie spełnia swojego zadania, jednak wraz ze stopniowym oczyszczaniem zdublowanych pozycji funkcjonalność ta powinna zacząć spełniać swoje zadanie i przynieść użytkownikowi dużą korzyść.

Jak na serwis społecznościowy przystało nie mogło zabraknąć funkcjonalności obserwowania. W LubimyCzytać.pl można obserwować innych czytelników, dzięki temu będziemy na bieżąco z książkami i ocenami obserwowanej osoby.

Chciałbym, aby serwis LubimyCzytać.pl stał się w pewnym sensie internetowym centrum wymiany informacji o książkach. Swoistym kompendium w którym miejsce znaleźliby zarówno namiętni czytelnicy jak i osoby nie czytające a jedynie szukające ciekawych książek na prezent.

Zapowiedzi funkcjonalności

Zdaję sobie sprawę, że w aktualnej wersji w serwisie brakuje wielu przydatnych funkcjonalności. Opublikowana wersja jest wersją bazową, która skupia się na najważniejszej funkcjonalności bez której serwis nie miałby sensu czyli wirtualnej biblioteczce.

Będziemy sukcesywnie dodawać kolejne funkcjonalności, na razie zrealizowaliśmy funkcjonalność „wklejki na stronę/wigeta” a w kolejce czekają następne:

  • dodawanie i edycja książek i autorów przez użytkowników,
  • fora/grupy tematyczne dla książek i autorów,
  • system rang użytkowników,
  • cykliczne konkursy,
  • integracja z księgarniami internetowymi,
  • komentowanie i ocenianie recenzji,
  • mini bazar kupię/sprzedam/wymienię,
  • tablica informacyjna o nadchodzących książkowych wydarzeniach,
  • integracja kont użytkowników z microblogami (blip, flaker, spinacz),
  • udostępnienie API,

i wiele innych… Jesteśmy otwarci na sugestie i propozycje współpracy :-)

Zapraszam na LubimyCzytać.pl

Serdecznie zapraszam do korzystania z serwisu. Wszelkie uwagi i komentarze dotyczące serwisu mile widziane.

Tani dobry hosting w USA – HostMonster

O tym, że nie ma w Polsce ofert hostingowych o przyzwoitym stosunku cena do możliwości, chyba nie muszę nikogo przekonywać.

Osobiście korzystam z usług dzielonego hostingu na NetArt i jestem względnie zadowolony, jednak limity typu 10gb pojemności konta czy brak dostępu przez ssh są dosyć irytujące.

Kiedyś przez 2 lata korzystałem z usług DreamHost.com, jednak 2-letni promocyjny okres się skończył a dosyć wysoka awaryjność ich serwerów (tempest, gambino) skutecznie zniechęciła mnie do przedłużania umowy.

Po niedługim czasie od wyprowadzki z DreamHost’a zatęskniłem za ssh i parametrami „Unlimited”, zacząłem mały research i moją uwagę przykuł mało znany w Polsce HostMonster.

Serwis hostingowy z typu „amerykańskich gigantów” za cenę $5,95 miesięcznie oferuje naprawdę dużo. Na HM user ma gwarantowane max. 64mb pamięci RAM i 30% mocy procesora. Mi osobiście szczególnie spodobała się obsługa baz danych PostgreSQL, gdyż jest to SZBD, który najbardziej przypadł mi do gustu i głównie na nim opieram swoje aplikacje. (Dreamhost jak i wiele topowych firm hostingowych oferuje jedynie MySQL.)

Muszę przyznać, że HostMonster oferuje nieco mniej fajerwerków niż DreamHost chociażby limit na instalacje niektórych programów unixowych, brak SVN i pewnie jeszcze kilka niekoniecznie ważnych ficzerów. Brak tych wszystkich funkcjonalności rekompensuje stabilność działania serwera a to przecież jest najważniejsze.

Po około trzech miesiącach użytkowania jestem bardzo zadowolony z ich usług, wszystko działa należycie, nie było żadnych padów a support szybciutko odpowiadał na pytania.

Zatem polecam HostMonster jako tani dzielony hosting dla serwisów nie wymagających mega małych pingów. Abonament za hosting można obniżyć do bajecznie niskich $3,95 na miesiąc korzystając z wielu dostępnych w necie HostMonster coupon codes. Za max. 150zł rocznie mocny, stabilny hosting z większością parametrów „unlimited” i dostępem ssh… dla mnie rewelacja.


Relecyjna baza ‘ala MySQL’ w chmurze Amazon AWS

Amazon w ramach AWS (Amazon Web Services) uruchomił publiczną wersję beta usługi relacyjnaj bazy danych 'ala MySQL’ (Amazon RDS) w swojej chmurze.

Amazon RDS ma cechować się:

  • prostotą konfiguracji i wdrożenia do aplikacji,
  • pełną kompatybilnością z bazą danych MySQL,
  • prostotą w zarządzaniu bazami, backupami i dostępnymi narzędziami,
  • pełną automatyką w backup’owaniu i czynnościach serwisowych,
  • skalowalnością w zależności od potrzeb uzytkownika
  • niezawodnością
  • bardzo dostępną ceną, tak jak w przypadku innych usług developerzy kasowani będą jedynie za zaosby, które rzeczywiście zużywają ich aplikacje.

Czy rzeczywiście tak będzie? Mam nadzieje. Przeczytaj więcej o Amazon RDS.

Usunięcie nieużywanych tagów z bazy WordPress’a

Czasami zachodzi potrzeba „ręcznego” kasowania postów z WordPress’a, jako że system ten działa na MySQL MyISAM to nie wspiera kaskadowego kasowania zależnych danych.

Skasowanie postów jest stosunkowo proste:

DELETE FROM wp_posts WHERE conditions;

Trudniejsza sprawa jest ze skasowaniem tagów. Na necie znalazłem poniższe zapytanie, działa wyśmielicie:

DELETE a,b,c
FROM
	wp_terms AS a
	LEFT JOIN wp_term_taxonomy AS c ON a.term_id = c.term_id
	LEFT JOIN wp_term_relationships AS b ON b.term_taxonomy_id = c.term_taxonomy_id
WHERE (
	c.taxonomy = 'post_tag' AND
	c.count = 0
	);

Czasami jednak pole „count” w relacji „wp_term_taxonomy” zawiera niepoprawne dane (liczbę większą od 0), wtedy nieużywane tagi musimy zidentyfikować poprzez LEFT JOINa z warunkiem ID IS NULL. Poniżej zapytanie wyświetlające nieużywane tagi.

SELECT DISTINCT wp_terms.slug FROM wp_terms wt
	INNER JOIN wp_term_taxonomy wtt ON wt.term_id=wtt.term_id
	INNER JOIN wp_term_relationships wtr ON wtr.term_taxonomy_id=wtt.term_taxonomy_id
	LEFT JOIN wp_posts wp ON wp.ID=wtr.object_id
WHERE
	taxonomy='post_tag'
AND 
	ID IS NULL
AND 
	NOT EXISTS(SELECT * FROM wp_terms wt2
                INNER JOIN wp_term_taxonomy wtt2 ON wt2.term_id=wtt2.term_id WHERE wtt2.parent=wt.term_id)
ORDER BY name