
W ostatni czwartek miałem przyjemność ogłosić prezentację na comiesięcznym spotkaniu LRUG (Łódź Ruby User Group). Prezentacja odnosiła się do technologii Elastic Search, która pozwala na szybkie przeszukiwanie i wstępną analizę danych – bardzo dużych ilości danych;-) Artykuł, który czytasz to pewne odwzorowanie tego co mówiłem na LRUGu, ale oprócz tego zamieszczam również samą prezentację, którą można pobrać tutaj, a także przykładowy projekt, na którym można poćwiczyć. Wszystko dostępne w zasobach;-)
LRUG
Na początku chciałbym powiedzieć kilka słów na temat samych spotkań – jeśli Cię to nie interesuje i chcesz jedynie przeczytać o Elastic Searchu – po prostu przejdź do punktu „Elastic Search – podstawy”;-).
Łódź w ostatnim czasie pod względem spotkań (meetupów) technologicznych mocno się rozwija. Ostatnio spadł na mnie zaszczyt dołożyć do tego cegiełkę, ponieważ objąłem organizację jednego z nich. LRUGi koncentrują się wokół szeroko pojętej technologii Ruby on Rails, chociaż tak naprawdę na naszych spotkaniach można zdobyć wiedzę z szerokiego zakresu;-) Tu zawsze jest ciekawie i zawsze – przede wszystkim – do bólu praktycznie. Przychodząc na nasze spotkania możesz spodziewać się jednego: wyjdziesz z nich z wiedzą, którą następnego dnia będziesz mógł zastosować – albo przynajmniej spróbować. Przykład?Poza omawianym tutaj Elastic Searchem, jedna z prezentacji dotyczyła bazy danych, która może pomóc Ci w stworzeniu zsynchronizowanych aplikacji – mobilnej, oraz „przeglądarkowej”. Bywa też zabawnie – jak na ostatnim spotkaniu, gdy Maciek pokazał jak w najgorszy i najbardziej niepraktyczny, ale zarazem najbardziej pomysłowy sposób zamienić liczby arabskie na rzymskie. Wykorzystał do tego narzędzia, o jakich filozofom się nie śniło;-)
Ale LRUGi to nie tylko konkretna dawka wiedzy. Z pewnością będziesz zachwycony (lub zachwycona! Dziewczyny są tu bardzo mile widziane;-)) atmosferą. Tutaj każdy może porozmawiać z każdym, a prelegenci w przerwach służą swoją wiedzą. Dodatkowo czas na naszych spotkaniach umilają pizza i piwo – oczywiście w zdrowych ilościach;-).
Jeśli więc interesujesz się IT i chcesz pożytecznie spędzić czas w towarzystwie ludzi, którzy są do ciebie podobni – po prostu przyjdź:-) Wszystkie informacje zawsze na bieżąco znajdziesz na profilu fb LRUGa – o tutaj. Polubić warto go także z innej prostej przyczyny – publikujemy tu naprawdę przydatne informacje. Nie tylko techniczne! Ostatnio mogłeś przeczytać u nas jak przygotować się do Lightning Talków, a niebawem będzie trochę informacji ze świata Ruby on Rails. Zapraszam jeszcze raz – spotykajmy się co miesiąc!
Elastic Search – podstawy
No to możemy przejść do Elastic Searcha. Oficjalnie o ES mówi się, że to Full-text search engine. Czyli po prostu technologia, która pomaga bardzo szybko wyszukiwać i wstępnie przetwarzać ilości danych. Naprawdę duże ilości danych! Pozwól, że kilka rzeczy napiszę, które mam nadzieję jakoś pokażą czym Elastic jest.
- Wyszukiwarki full-text search – Dzięki Elasticowi można przede wszystkim zrobić „inteligentne” wyszukiwarki, które trochę „domyślają się” co naprawdę chcesz wyszukać.
- Big Data – Bardzo popularny i modny temat. Tak! Elastic Search jest technologią Big Datową, a to znaczy, że radzi sobie z bardzo dużymi ilościami danych
- Rozbudowane środowisko – Do „grupy Elastica” należy również Kibana, oraz Logstash. Ta pierwsza udostępnia ładny interfejs dla wyszukiwanych danych, natomiast Logstash pomaga w przetwarzaniu logów.
Jak już Cię zachęciłem (zachęciłem, prawda?), to teraz z chęcią rozpiszę bardzo krótko budowę Elastic Searcha. Na samym początku warto wspomnieć, że ES zbudowany jest wokół nierelacyjnej bazy danych.
Cluster – na samej górze w hierarchii stoi klaster. On spaja wszystkie serwery. Ma swoją nazwę – domyślnie elasticsearch (jeśli odpalasz ES na macu, to domyślnie nazwą jest elasticsearch_twojanazwa).
Node – czyli po prostu serwer. Elasticsearch może działać na kilku serwerach, ale my wykorzystamy tylko jednego noda. Lokalnie odpalany jest standardowo na porcie 9200. Node też ma swoją nazwę i ciekawostka może być przysmakiem dla koneserów komiksów, bowiem domyślnie nazwa losowana jest ze zbioru imion… bohaterów komiksów Marvela 😉
Index – kolekcja dokumentów. To w przybliżeniu odpowiednik tabeli w bazie relacyjnej.
Document – dokument jest najmniejszą jednostką Elastica. To odpowiednik rekordu w bazie relacyjnej. Ma swoje pola – takie jak imię, nazwa, wiek itd.
Instalacja i uruchamianie Elastic Searcha
Skoro znasz już budowę, warto zabrać się za „samo gęste”. Jeśli jesteś na macu, zainstaluj Elastic Searcha przez
brew install elasticsearch.
Być może będziesz musiał doinstalować jakieś javowe rzeczy, ale nie powinno być z tym zasadniczo problemu. Jeśli korzystasz z Linuxa – w tym artykule wyjaśnione jest jak to załatwić;-)
Gdy już zainstalowałeś (sama instalacja trwa około 5-7 minut, możesz więc śmiało iść zaparzyć sobie kawę, albo przeczytać jakiś inny fajny artykuł na IT-Blogu Wolnego Człowieka;-) ), uruchamiamy za pomocą prostej komendy elasticsearch. W tym momencie ES zostanie włączony w trybie developerskim (będziesz mógł podglądać logi Noda) na porcie nr 9200. Jeśli chcesz podstawowe informacje na jego temat – wejdź po prostu w przeglądarce na http://localhost:9200.
Operacje na dokumentach (komunikacja z Elastic Search)
Zanim przejdziemy do wyszukiwania, musimy mieć co wyszukiwać. W tym celu nauczymy się kilku podstawowych rzeczy – indexowania, pobierania, oraz usuwania danych w ES.
Indexowanie – to po prostu dodawanie dokumentu do indexu. Aby to zrobić, musimy uderzyć metodą PUT na następujący adres:
http://localhost:9200/index/typ/id
W tym celu użyjemy CURLa. Wejdź do swojego terminala/konsoli i wpisz następujące polecenie.
1 2 3 4 5 6 7 |
curl -XPUT "http://localhost:9200/employees/employee/1" -d' { "name": "Daria Woźnicka", "level": "Senior", "salary": 100000, "sex": "woman" }' |
W tym momencie dodaliśmy dokument do bazy Elastica. Brawo! Pierwsza operacja zrobiona. Teraz jeszcze dwie, które są bliźniaczo podobne, więc napiszę tylko wzór na nie.
Pobieranie po id – żeby wyciągnąć z bazy jakiś element po prostu uderzamy na taki sam adres, z tą różnicą, że robimy to z metodą GET, oraz nie podajemi żadnych danych.
1 |
curl -XGET "http://localhost:9200/employees/employee/1" |
Usuwanie dokumentu – to niemal identyczna operacja. Na powyższy adres uderzamy metodą DELETE
1 |
curl -XDELETE "http://localhost:9200/employees/employee/1" |
Wyszukiwanie
No, nareszcie! Czas wziąć się za to co najfajniejsze, czyli za wyszukiwanie rzeczy, które chcemy znaleźć. Najpierw jednak zachęcam Cię do „zaaplikowania” dokumentów, które przygotowałem. To typowy zbiór pracowników jakiejś firmy, z kilkoma stopniami. Odpowiednie polecenia znajdziesz samym dole artykułu. Ja będę wyszukiwał właśnie na tym zbiorze.
Aby to zrobić, musimy wysłać zapytanie na endpoint _search, jako dane podajemy „query”, a następnie rodzaje query. My posłużymy się „query_string”. Na początek znajdźmy może… ludzi, którzy są juniorami?
1 2 3 4 5 6 7 8 |
curl -XPOST "http://localhost:9200/_search" -d' { "query":{ "query_string":{ "query": "junior" } } }' |
Gratulacje! Spójrz na wynik, jaki dostałeś. Bardzo ważną rzeczą, o której chcę powiedzieć, to scores. Właściwie to jedna z najważniejszych rzeczy tutaj – Elasticsearch oblicza jak ważny jest dany dokument w aspekcie twojego wyszukania i do każdego wyniku podaje swoją punktację. No dobrze… ale w wyniku, któy dostaliśmy są przecież dwa dokumenty. I bynajmniej oba nie są juniorami!
Co dostaliśmy:
- Jan Kowalski – dokument, która faktycznie jest juniorem, oraz…
- George Bush Junior – ten z kolei jest seniorem. O nie! Przecież chcieliśmy wyszukać juniora, a Elastic Search wziął pod uwagę wszystkie pola dokumentu. Co z tym fantem zrobić?
Możemy na przykład zbudować nowe query – tym razem powiemy Elasticowi, żeby patrzył tylko na pole „level” ; – )
1 2 3 4 5 6 7 8 9 |
curl -XPOST "http://localhost:9200/_search" -d' { "query":{ "query":{ "query_string": "junior", "fields": ["level"] } } }' |
Prawda, że proste? Po wysłaniu takiego zapytania, nie mamy już problemu z otrzymaniem prawidłowej odpowiedzi;-)
Elastic Search w Ruby on Rails
Skoro już wiemy co i jak, przejdźmy do integracji ES z naszą aplikacją napisaną w technologii Ruby on Rails. To naprawdę prosta sprawa, tylko trzeba przejść kilka łatwych kroków. Będę do tego wykorzystywał aplikację, którą napisałem specjalnie dla każdego, kto chce się nauczyć Elastic Searcha od podstaw. Można ją pobrać z mojego githuba (o, tutaj). Aplikacja Companies Legerin ma dwie branche – master, oraz elasticsearch. Master jest zupełnie „goła” – ma jedynie model Company i oddpowiednio skonfigurowaną aplikację, aby można było łatwo zacząć naukę Elastica. Na drugiej branchy ES jest już zainstalowany – wersja dla leniwych;-)
Dodatkowo dołożyłm bazę danych. Aby ją wczytać, należy wejść w główny folder aplikacji i w konsoli (zwykłej, nie railsowej) utworzyć bazę danych ( bundle exec rails c ), a następnei wywołać komendę
sqlite3 db/development.sqlite3 < database.sql
Integracja
Sprawa z integracją ma się prosto. Korzystamy z trzech gemów:
1 2 3 |
gem 'elasticsearch-model', git: 'https://github.com/elastic/elasticsearch-rails.git' gem 'elasticsearch-rails', git: 'https://github.com/elastic/elasticsearch-rails.git' gem 'elasticsearch-persistence', git: 'https://github.com/elastic/elasticsearch-rails.git' |
W aplikacji będziemy musieli wskazać, które dane ES ma zapisywać. W tym celu idziemy do wybranego modelu – w naszym przypadku to model Company – i wpisujemy następujące rzeczy na początku klasy.
1 2 3 |
include Elasticsearch::Model include Elasticsearch::Model::Callbacks index_name "companies" |
Dzięki pierwszym dwóm bibliotekom możemy korzystać z Elastic Searcha na tym modelu, oraz będzie on przeinddexowywał bazę danych (swoją) przy każdym callbacku – czyli jeśli zapiszemu, usuniemy, lub updatujemy nasz obiekt modelu Company. Na samym końcu dodajemy index_name i wskazujemy jak ma się nazywać nasz index.
Kolejna rzecz to dodanie metody as_index_json. Tutaj określamy jakie pola ma zapisywać w swojej bazie ES.
1 2 3 4 5 |
def as_indexed_json(options={}) self.as_json({ only: [:name, :description, :id, :income, :employee_amount, :address], }) end |
Ostatnim krokiem jest uruchomienie konsoli railsowej i wrzucenie następujących dwóch poleceń:
1 2 |
Company.__elasticsearch__.create_index! Company.__elasticsearch__.import(force: true) |
To zasadniczo tyle;-) Od teraz można korzystać z Elastic Searcha w aplikacji.
Wyszukiwanie w aplikacji
Od teraz możemy zbudować naszą pierwszą metodę, która będzie wyszukiwać. dokumenty z podaną przez nas frazą.
1 2 3 4 5 6 7 8 9 10 11 |
def self.search_by_query_string(query) __elasticsearch__.search( { query: { query_string: { query: query } } } ) end |
Jako argument pozwalamy podać jakąś frazę, po której będziemy przeszukiwać. __elasticsearch__.search() to nic innego, jak właśnie uderzenie na endpoint _search – robiliśmy to wyżej, na sucho;-) Dalej jest już tylko to, co znasz.
Zrómy jakąś bardziej zaawansowaną metodę!
Pozwolimy użytkownikowi wyszukać dokumenty wykorzystując nazwę firmy, opis, oraz adres, ale opis będziemy chcieli wzmocnić. Dodatkowo – co ważne – chcemy, aby wyszukiwało dokumenty nawet, jeśli użytkownik NIE WPISZE PEŁNEJ NAZWY. I tu wchodzimy w magię ES – przyjrzyjmy się poniższej metodzie.
1 2 3 4 5 6 7 8 9 10 11 12 |
def self.search_by_part_of_phrase(query) __elasticsearch__.search( { query: { query_string: { query: "*#{query}*", fields: ['name', 'description^5', 'address'] } } } ) end |
- Standardowo dajemy query. Ale dodatkowo po obu stronach wrzucamy gwiazdki (*). Te gwiazdki to tzw. wildcardy i mówią Elastic Searchowi, z której strony ma się „domyślać” reszty wyrazu. Jeśli więc wstawimy tylko po prawej stronie („#{query}*”), to po wpisaniu „Micro” dostaniemy dokument z danymi firmy „Microsoft”, jednak jeśli wpiszemy „soft”, nie znajdzie już pożądanej firmy. Wrzucamy więc gwiazdki po obu stronach i cieszymy się tym, że mamy możliwość wyszukiwania naszych firm po podanej niepełnej frazie.
- fields – tutaj pojawia się również dziwny znak (^). Dzięki niemu mówimy Elastic Searchowi, że to pole powinno być silniejsze (tzw. boost). Jeśli więc w jakiejś firmie szukana fraza pojawi się kilka razy w polu description, będzie ona (ta firma) szczególnie silna.
Teraz przejdź do konsoli i wywołaj te metody. Wywołajmy sobie ostatnią – Company.search_by_part_of_phrase(„Micro”).
Woow! Co za wynik! O co tu chodzi?! Spokojnie, na wyniku możemy zrobić kilka rzeczy, przede wszystkim dwie.
- Na wyniku możemy wywołać .results – pozwoli nam to na zdobycie wcześniej poznanych informacji (przede wszystkim scores tam będą).Wywołaj więc
1Company.search_by_part_of_phrase("Micro").results.to_a.
Pozwoli to na zdobycie wyników w tablicy. - Na wyniku możemy wywołać .records – to z kolei zwróci obiekty railsowe, gotowe do użycia w aplikacji. Wywołaj również tak, żeby mieć je zebrane w tablicy
1Company.search_by_part_of_phrase("Micro").records.to_a
To tyle!
To byłoby na tyle. Sądzę, że jeśli opanujesz (i zrozumiesz!) to co jest w tym artykule, to będzie to bardzo fajny wstęp do pracy z Elastic Searchem. Polecam eksperymenty, pracować możesz bez przeszkód na moim projekcie, który udostępniłem na githubie. Jeśli masz jakiekolwiek pytania – napisz śmiało do mnie na maila, na facebooku, lub w komentarzu, a ja postaram się pomóc:-) No i do zobaczenia na następnym LRUGu! Prezentację z LRUGa, oraz github znajdziesz w zasobach.
Ja nazywam się Marek Czuma, a to jest IT-Blog Wolnego Człowieka
Piszę do Ciebie Prosto z Łodzi
Jeśli uważasz, że artykuł był pomocny, lub po prostu lubisz być kreatywnym w IT – polub mój Fanpage na Facebook’u. Zapraszam do zostawienia maila – zero spamu, 100% dobrych treści.
A to wspomniane dane. Po prostu je przekopiuj do swojej konsoli – dzięki nim będziesz mieć większe pole do przeszukiwania.
1 2 3 4 5 6 7 8 9 10 11 12 |
curl -XPUT "http://localhost:9200/employees/employee/1" -d' {"name": "Jessica Jones", "level": "Senior", "salary": 100000, "sex": "woman" }' curl -XPUT "http://localhost:9200/employees/employee/2" -d' {"name": "Paweł Kukiz", "level": "Beginer", "salary": 10, "sex": "man" }' curl -XPUT "http://localhost:9200/employees/employee/3" -d' {"name": "Ronald Reagan", "level": "Senior", "salary": 90000, "sex": "man" }' curl -XPUT "http://localhost:9200/employees/employee/4" -d' {"name": "Steve Jobs", "level": "Mid1", "salary": 15, "sex": "man" }' curl -XPUT "http://localhost:9200/employees/employee/5" -d' {"name": "Bill Clinton", "level": "Mid3", "salary": 4000, "sex": "woman" }' curl -XPUT "http://localhost:9200/employees/employee/6" -d' {"name": "Elon Musk", "level": "Senior", "salary": 24000, "sex": "man" }' curl -XPUT "http://localhost:9200/employees/employee/7" -d' {"name": "Marek Czuma", "level": "Beginer", "salary": 0, "sex": "man" }' curl -XPUT "http://localhost:9200/employees/employee/8" -d' {"name": "Hayley Williams", "level": "Senior", "salary": 0, "sex": "man" }' curl -XPUT "http://localhost:9200/employees/employee/9" -d' {"name": "Lana Del Rey", "level": "Mid3", "salary": 70000, "sex": "man" }' curl -XPUT "http://localhost:9200/employees/employee/10" -d' {"name": "Jennifer Lawrence", "level": "Mid1", "salary": 2000, "sex": "man" }' curl -XPUT "http://localhost:9200/employees/employee/11" -d' {"name": "Goerge Bush Junior", "level": "Senior", "salary": 2000, "sex": "man" }' curl -XPUT "http://localhost:9200/employees/employee/12" -d' {"name": "Jan Kowalski", "level": "Junior", "salary": 200, "sex": "man" }' |
Bylem nieobecny przez jakis czas, ale teraz pamietam dlaczego ja lubilem te witryne. Dzieki, sprobuje byc czesciej
Całkowicie zgadzam się z autorem tekstu. Duża wiedza.