W artykule podsumowującym rok 2017 napisałem, że w 2018 roku ukaże się, na moim blogu, znacznie więcej treści dotyczących chmury publicznej Microsoft Azure. Niestety, w obecnej chwili, nie pozostaje mi nic innego jak tylko uderzyć się w pierś. Końcówka roku za pasem, a to dopiero pierwszy artykuł w temacie. Obiecuje poprawę i na znak mojej skruchy, w dzisiejszym artykule przedstawię wam ciekawą usługę oferowaną przez Microsoft. Azure Search - pozwala nam stworzyć rozbudowaną wyszukiwarkę do naszej aplikacji. Ktokolwiek musiał napisać system wyszukiwania wie, że nie jest to proste zadanie. Tym bardziej, gdy skala projektu rośnie, aż przestajemy mieć możliwość latania operacjami "like" na bazie danych. Nie chcąc stawiać własnych serwerów ElasticSearch-a łapiemy za kakałko i ogarniamy Azure Search.
Czym jest Azure Search?
Na stronie producenta możemy przeczytać pięknie brzmiący opis:
Oparta na technologii AI usługa wyszukiwania w chmurze do tworzenia aplikacji internetowych i aplikacji mobilnych
- Wzbogacanie i wyodrębnianie szczegółowych informacji dzięki umiejętnościom poznawczym
- Szybkie rozpoczynanie pracy z indeksami wyszukiwania
- Łatwe skalowanie w górę i w dół
- Łączenie wyników wyszukiwania z celami biznesowymi przy zachowaniu ścisłej kontroli klasyfikacji wyszukiwania
- Korzystanie z dogłębnej wiedzy firmy Microsoft na temat przetwarzania języka naturalnego
- Łatwe dodawanie wyszukiwania geoprzestrzennego do aplikacji
Tak po ludzku zaś: jest to usługa Search as a Service. Pozwala nam podpiąć źródło danych, ewentualnie wykorzystać api REST-owe do uzupełniania danych, skonfigurować po jakich polach ma indeksować i gotowe. No prawie. Czeka nas jeszcze napisanie zapytania do usługi, ale z pomocą przychodzi nam, dostępna jako paczka w nuget - cie, biblioteka od Microsoft-u.
Chwila, chwila, chwila, jeszcze jedna sprawa - Azure Search przechowuje dane w postaci dokumentów klucz : wartość, gdzie jako wartość mogą być użyte bardziej skomplikowane obiekty niż stringi, jak na przykład kolekcję etc. (bardzo podobnie jak w bazach NoSQL).
Use Case
Implementacja usługi Azure Search różni się od przyszłego zastosowania, przypadków użycia etc. Mamy dwa podejścia do zdefiniowania źródła danych dla wyszukiwarki:
- Usługę wewnątrz Azure tak jak np. CosmosDB
- Indeksowanie elementów za pomocą REST API
Rozpisanie się na temat obu opcji wymagałoby od was wręcz mistycznej woli by to przeczytać. Nie oszukując - już pierwszy element będzie wystarczająco testował wasze zaangażowanie w temat. Krótko i zwięźle - będzie długi tekst i tak, więc pokaże wam "tylko" jak w prosty sposób skonfigurować CosmosDB i Azure Search tak, by Search automatycznie indeksował nowo pojawiające się dokumenty w CosmosDB.
Tworzymy bazę CosmosDB
Zacznijmy od stworzenia bazy, która posłuży nam jako źródło danych. Wystarczy na portalu kliknąć w przycisk "Create Resource", taki duży zielony plus po lewej stronie. Następnie wyszukać CosmosDB. Przechodzimy do panelu, w którym uzupełniamy podstawowe informacje o naszym koncie bazy danych. W moim przypadku wygląda to następująco.
Zdecydowałem się na wykorzystanie API SQL, ponieważ na obecną chwilę tylko ono wspiera integrację z Azure Search :( Wsparcie dla integracji MongoDB API jest już w publicznym preview więc pewnie niedługo będziemy mogli je testować.
Masz odrazę do przeglądarek internetowych? Fascynuje cie konsola? Do stworzenia bazy możesz wykorzystać azure cli! Wystarczy wpisać poniższy kod w konsoli, mocno kliknąć w przycisk enter, wyjść zrobić sobie kakałko, wypić, poczytać gazetę i jak wrócimy do naszego komputera to już nowiutka baza stoi i czeka na dalsze rozkazy.
az cosmosdb create \
--name testdbforblogpost \
--location "North Europe"=0 "West Europe"=1 \
--resource-group blog-search-post \
--max-interval 10 \
--max-staleness-prefix 200
Niestety, sama baza, a w zasadzie jej konto, nie wystarczy. Potrzebujemy jeszcze prawdziwej fizycznej bazy i kolekcji. Ogarniamy to za pomocą portalu Azure
Wystarczy, że klikniemy w przycisk "Add Collection" i wtedy przejdziemy do zakładki "Data Explorer"
W jednym formularzu stworzymy zarówno kolekcję jak i bazę danych. Osobiście wybrałem drugą, prostszą drogę. Nie wspomniałem, że taka jest i nie trzeba tego wszystkiego przeklikiwać? Nauka na dziś - czytać całość zanim się siądzie do pracy. Poprzez zakładkę "Quick Start" generuje przykładową baze danych.
Jednak dla wszystkich osób, którzy kochają konsolę, fajniejszy będzie trzeci sposób (oczywiście, ze musi być wersja konsolowa!). Ponownie możemy wykorzystać azure cli.
az cosmosdb database create \
--name testdbforblogpost \
--db-name search \
--resource-group blog-search-post \
az cosmosdb collection create \
--collection-name articles \
--name testdbforblogpost \
--db-name search \
--resource-group blog-search-post \
--throughput 400
Do testowania testowych danych do bazy wykorzystałem mechanizm upload-u plik JSON, który możecie znaleźć w zakładce "Data Explorer". Następnie używając narzędzia JSON Generator stworzyłem 4 itemy według poniższej definicji:
[
{
'repeat(4)': {
title: '{{lorem(3, "words")}}',
picture: 'http://placehold.it/32x32',
author: {
first: '{{firstName()}}',
last: '{{surname()}}'
},
description: '{{lorem(1, "paragraphs")}}',
tags: [
{
'repeat(5)': '{{lorem(1, "words")}}'
}
]
}
}
]
Jak widać struktura dokumentu nie jest zbyt skomplikowana, jednak zawiera zagnieżdżony obiekt oraz kolekcję tagów.
Uruchomienie usługi Azure Search
Kto nie skacze ten nie ma wygenerowanej usługi Azure Search! Tak, nie musicie skakać. Tak, musiałem kilka razy podskoczyć. Kto mnie widział, ten wie, dlaczego ten żart kosztował mnie spoooro wysiłku. No dobra, do roboty, najpierw tworzymy zasób. W portalu Azure klikamy "Create a resource" i wyszukujemy "Azure Search". Dzi ęki temu zostaniemy przeniesieni do panelu konfiguracyjnego nowej usługi.
Tutaj czeka nas bardzo miła niespodzianka. Usługa Azure Search jest dostępna w Free Tier, więc jeżeli chcecie ją wypróbować to nie musicie ponosić zbędnych kosztów. Naprawdę polecam.
Połączenie CosmosDB z Azure Search
No to mamy już stworzoną bazę CosmosDB jak i usługę Azure Search. Czas na połączenie obu usług. Są na to dwa sposoby: prawie identyczne, tylko w jednym pijesz kakałko zanim siądziesz do pracy. Preferuje ten z ciepłym napojem. Dalsze kroki są proste: musimy wrócić do panelu naszej bazy. Tam w menu Settings jest taki magiczny przycisk "Add Azure Search".
Po kliknięciu w niego przechodzimy do konfiguracji połączenia. Trzeba będzie wybrać jaką instancję usługi Azure Search chcemy użyć. Nie jest to nic trudnego, dlatego też pominąłem ten krok w screen-ach.
Przejdźmy do ciekawszych rzeczy. Już w drugiej sekcji panelu definiujemy źródło danych, które będzie zasilać silnik wyszukiwania. Musimy przejść do sekcji Cosmos DB, gdzie z list rozwijanych wybieramy bazę i kolekcję elementów (w takiej ścieżce nie da się ustawić pobierania z wielu kolekcji na raz).
Najciekawszą opcją jest pole "Query", dla uproszczenia przykładu zostawiłem je z default-ową wartością. W przypadku gdy nasze dokumenty posiadają zagnieżdżone obiekty konieczne będzie wpisania komendy SQL spłaszczającej nam strukturę, czyli np. z takiego dokumentu:
{
"title": "Test",
"author": {
"firstName": "Kamil",
"lastName": "Bd90"
}
}
Zrobi następujący:
{
"title": "Test",
"author.firstName": "Kamil",
"author.lastName": "Bd90"
}
Na szczęście Azure Search obsługuję kolekcję elementów normalnie.
Po tym etapie można powiedzieć, że najgorsze za nami :) Jako, że w tym przykładzie nie omówimy usług kognitywnych np. do analizy słów kluczowych w szukanym tekście, krok numer 3 w konfiguracji możemy pominąć. Jeżeli chcecie poczytać kiedyś jak połączyć usługi kognitywne z usługą Azure Search dajcie znać w komentarzach :)
Definicja Indexer-a
Jedziemy do ostatniego etapu! Konfigurujemy sam indexer. Indexer jest elementem usługi Azure Search, w którym definiujemy takie elementy jak:
- klucz Główny;
- pola mające trafić do zaindeksowania;
- sposób obrabiania danych;
- typ danych kryjący się pod odpowiednim polem;
Jak widzicie na powyższym obrazku, definicja indexera nie jest taka trudna. Azure nam w tym mocno pomaga, sam sczytał wszystkie obsługiwane pola z dokumentów CosmosDB i sprawdził ich typy danych. Dzięki temu wygenerował tabelkę z pięcioma kolumnami. Teraz przejrzyjmy szybko, co każda z tych kolumienek oznacza:
- Retrievable - dane będą zwracane w json-ie z odpowiedzią;
- Filterable - za pomocą składni zapytań możemy filtrować wyniki np. (Pobrać tylko po danym tagu etc.);
- Sortable - sortowanie po danym polu listę wyników;
- Searchable - pole będzie przeszukiwane w celu znalezienia szukanej frazy;
- Facetable - po danym polu będzie można grupować / kategoryzować wyniki;
W tym momencie muszę wtrącić myśl, którą uważam za tak ważną, że aż obejmę ją w blok cytatu:
Do raz wygenerowanego indeksu można dodawać nowe i usuwać stare pola. Nie można jednak edytować oznaczeń, np. czy po danym polu można sortować itp. Wymaga to utworzenia nowego indexer-a wraz z zaindeksowaniem wszystkich elementów od nowa.
To ważna lekcja. Brutalnie mi przedstawiona. Nie boli, gdy mamy jakieś 20 000 elementów do ponownego zaindeksowania, jednak 20 000 000 to już poczujecie :(
Testowanie wyników wyszukiwania
Dobrze, skoro mamy już wszystko skonfigurowane, możemy przejść to testowania. Jak wrócimy do naszego panelu usługi Azure Search to kliknięcie w indexer odpali nam poniższy panel.
Oczywiście, aby prawa strona otworzyła się trzeba kliknąć w "Search Explorer". W polu "query string" możemy wpisywać nasze zapytania. Tutaj będą działały wszystkie specjalne zapytania jak zaprezentowana powyżej "*". Ze składnią tych zapytań możecie się zapoznać w dokumentacji Azure Search-a, gdzie wszystko zostało precyzyjnie wyjaśnione.
Podsumowanie
To tyle na dzisiaj. Poruszyliśmy tutaj całkiem sporo kwestii. Serio spooorooooo. W następnym artykule na temat Azure Search opiszę jak wykorzystać jego API REST-owe aby z poziomu kodu wysyłać dane do zaindeksowania. Na pewno będzie ciekawie i w końcu będzie trochę kodu do napisania :)
Mam nadzieje, że wpis się podobał.
Do Następnego!
Cześć