Elasticsearch w projektach Java – RESTful API przez HTTP
Zaktualizowaliśmy ten tekst dla Ciebie!
Data aktualizacji: 10.12.2024
Autor aktualizacji: Miłosz Nowak
Poprzednie artykuły koncentrują się na komunikacji z Elasticsearch za pomocą Java Rest High Level Client. Ten artykuł przedstawia komunikację za pomocą RESTful API przez HTTP z użyciem klienta internetowego Postman. Jest to bardzo przydatne narzędzie do testowania REST API, gdzie możesz samodzielnie eksperymentować z dostarczonymi poleceniami. W tym artykule omówiono wszystkie czynności związane z indeksami lub dokumentami, które zostały wykonane przy użyciu Java API, abyś mógł łatwo zobaczyć, jak się one do siebie odnoszą.
Od Elasticsearch 8.x zaleca się korzystanie z Elasticsearch Java Client jako nowszego i wspieranego rozwiązania zamiast Java Rest High Level Client.
RESTful API
Jednym ze sposobów komunikacji z Elasticsearch jest używanie RESTful API przez protokół HTTP za pośrednictwem domyślnego portu 9200. Elasticsearch oferuje szeroki zestaw API z bardzo szczegółową dokumentacją dla każdego, które można bezpośrednio wykorzystać do konfigurowania i uzyskiwania dostępu do funkcji Elasticsearch. Poniżej znajduje się oficjalna dokumentacja:
Wiele Elasticsearch GET API – a szczególnie API wyszukiwania – obsługuje ciało żądania. Chociaż akcja GET ma sens w kontekście pobierania informacji, żądania GET z ciałem nie są obsługiwane przez wszystkie biblioteki HTTP. Wszystkie Elasticsearch GET API, które wymagają ciała, mogą być również przesyłane jako żądania POST.
Zaczynając od początku, to polecenie można wykorzystać do wyświetlenia szczegółów uruchomionej instancji oraz informacji o klastrze.
GET localhost:9200/?pretty
W rezultacie otrzymuje się odpowiedź podobną do poniższej, zawierającą takie informacje jak:
- nazwa hosta maszyny to „MARLAP”
- domyślna nazwa klastra Elasticsearch to „elasticsearch”
- uruchomiona wersja Elasticsearch to 7.10.2
{
"name": "MARLAP",
"cluster_name": "elasticsearch",
"cluster_uuid": "zPXUxzVjRBerDRNTG0xpZA",
"version": {
"number": "7.10.2",
"build_flavor": "default",
"build_type": "zip",
"build_hash": "747e1cc71def077253878a59143c1f785afa92b9",
"build_date": "2021-01-13T00:42:12.435326Z",
"build_snapshot": false,
"lucene_version": "8.7.0",
"minimum_wire_compatibility_version": "6.8.0",
"minimum_index_compatibility_version": "6.0.0-beta1"
},
"tagline": "You Know, for Search"
}
W tym artykule wszystkie podane zapytania stosują konwencję bez hosta i portu, dzięki czemu główna ścieżka komendy jest wyeksponowana, na przykład:
GET /<path>
Od tego miejsca wymienione są niektóre interfejsy API, które są używane do obsługi funkcjonalności aplikacji demonstracyjnej, wraz z odpowiednimi komendami oraz oczekiwanymi wynikami. Na końcu celem jest wzbogacenie danych driverów o pewne informacje statystyczne, podobnie jak to zostało zrealizowane za pomocą Java Rest High Level Client.
API Indeksu
Interfejsy API indeksu są używane do zarządzania poszczególnymi indeksami, ich ustawieniami, aliasami lub mapowaniami.
1. Tworzenie indeksu
Pierwszym krokiem jest utworzenie dwóch indeksów z sufiksami czasowymi db-statistics-20220105-142000 oraz db-enriched-drivers-20220105-142000, gdzie dane demonstracyjne zostaną zapisane, za pomocą następujących komend:
PUT /db-statistics-20220105-142000
PUT /db-enriched-drivers-20220105-142000
W wyniku wykonania polecenia można oczekiwać podobnej odpowiedzi:
{
"acknowledged": true,
"shards_acknowledged": true,
"index": "db-enriched-drivers-20220105-142000"
}
2. Pobieranie informacji o indeksie
Za pomocą poniższego polecenia można uzyskać główne informacje o indeksie:
GET /db-enriched-drivers-20220105-142000
W wyniku otrzymuje się odpowiedź zawierającą szczegóły dotyczące:
Aliasów: Nazwy alternatywne indeksu, które mogą ułatwić zarządzanie wersjonowaniem danych.
Mapowań: Definicji pól i typów danych przechowywanych w indeksie.
Ustawień: Konfiguracji indeksu, takich jak liczba shardów, replik i inne parametry.
{
"db-enriched-drivers-20220105-142000" : {
"aliases" : { },
"mappings" : { },
"settings" : {
"index" : {
"routing" : {
"allocation" : {
"include" : {
"_tier_preference" : "data_content"
}
}
},
"number_of_shards" : "1",
"provided_name" : "db-enriched-drivers-20220105-142000",
"creation_date" : "1641388937856",
"number_of_replicas" : "1",
"uuid" : "cdaMHbxVQ4eS_MTTZCqqyQ",
"version" : {
"created" : "7100299"
}
}
}
}
}
3. Usuwanie indeksu
Może się zdarzyć, że indeks trzeba usunąć, na przykład gdy nazwa jest nieprawidłowa lub indeks nie jest już potrzebny. W takim przypadku można użyć następującego polecenia:
DELETE /db-enriched-drivers-20220105-142000
Następnie, używając komendy z metodą HTTP GET, można sprawdzić, czy indeks został faktycznie usunięty. W przypadku powodzenia zostanie zwrócony błąd, podobny do poniższego.
{
"error": {
"root_cause": [
{
"type": "index_not_found_exception",
"reason": "no such index [db-enriched-drivers-20220105-142000]",
"resource.type": "index_or_alias",
"resource.id": "db-enriched-drivers-20220105-142000",
"index_uuid": "_na_",
"index": "db-enriched-drivers-20220105-142000"
}
],
"type": "index_not_found_exception",
"reason": "no such index [db-enriched-drivers-20220105-142000]",
"resource.type": "index_or_alias",
"resource.id": "db-enriched-drivers-20220105-142000",
"index_uuid": "_na_",
"index": "db-enriched-drivers-20220105-142000"
},
"status": 404
}
Po usunięciu należy ponownie utworzyć indeks db-enriched-drivers-20220105-142000, ponieważ będzie on potrzebny w dalszych krokach.
4. Sprawdzanie aliasów
Po utworzeniu indeksów można przypisać aliasy, aby nie trzeba było znać pełnej nazwy z oznaczeniem czasowym przy odwoływaniu się do konkretnego indeksu. Przed przypisaniem aliasów warto sprawdzić, czy istnieją już jakieś aliasy przypisane do stworzonych indeksów. Można to zrobić za pomocą zapytania z użyciem symbolu wieloznacznego:
GET /_alias/db-*
W wyniku otrzymuje się odpowiedź, która zawiera odpowiednie informacje. Na przykład:
{
"db-enriched-drivers-20220105-142000": {
"aliases": {
}
},
"db-statistics-20220105-142000": {
"aliases": {
}
}
}
Sprawdzanie informacji o jednym konkretnym aliasie
Czasami może być przydatne zapytanie o informacje dotyczące konkretnego aliasu. Można to zrobić za pomocą poniższego polecenia:
GET /_alias/db-enriched-drivers
Jeśli alias o nazwie db-enriched-drivers nie istnieje, w wyniku zapytania otrzymamy odpowiedź błędu:
{
"error": "alias [db-enriched-drivers] missing",
"status": 404
}
5. Tworzenie aliasu
Po sprawdzeniu, jakie aliasy istnieją, możemy potrzebować stworzyć alias dla konkretnego indeksu. Zapytanie zawiera nazwę indeksu i alias, który chcemy do niego przypisać. Dla wcześniej utworzonych indeksów, poniższe polecenia mogą być użyte:
PUT /db-statistics-20220105-142000/_alias/db-statistics
PUT /db-enriched-drivers-20220105-142000/_alias/db-enriched-drivers
PUT /db-enriched-drivers-20220105-142000/_alias/db-enriched-drivers
Po wykonaniu tych zapytań, możemy sprawdzić, czy aliasy zostały utworzone pomyślnie, wykonując zapytanie z punktu 4. Oczekiwana odpowiedź powinna wyglądać następująco:
{
"db-enriched-drivers-20220105-142000": {
"aliases": {
"db-enriched-drivers": {}
}
},
"db-statistics-20220105-142000": {
"aliases": {
"db-statistics": {}
}
}
}
6. Usuwanie aliasu
Gdy alias musi zostać usunięty z konkretnego indeksu, można użyć następującego polecenia:
DELETE /db-enriched-drivers-20220105-142000/_alias/db-enriched-drivers
Po wykonaniu tego zapytania, można sprawdzić, czy alias został usunięty, wykonując zapytanie z punktu 4.
7. Aktualizacja mapowania
Czasami może być przydatne wcześniejsze zdefiniowanie mapowania, aby silnik Elasticsearch wiedział, jak mapować pola z góry, chociaż domyślne mapowanie, wykonane po pierwszym zaindeksowaniu dokumentów, jest często wystarczające. Dla indeksu db-enriched-drivers zmieniono typ pól: code, driverId i nationality na keyword, aby możliwe było wykonywanie agregacji na tych polach.
Aby zaktualizować mapowanie, używane jest następujące zapytanie z ciałem żądania pokazanym poniżej:
PUT localhost:9200/db-enriched-drivers/_mapping
{
"properties": {
"code": {
"type": "keyword",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"driverId": {
"type": "keyword",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"nationality": {
"type": "keyword",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
Mapowanie dla dowolnego zapytania można sprawdzić, używając następującego polecenia:
GET /<index_name>/_mapping
Enrich API
Enrich API służy do zarządzania politykami wzbogacania danych.
1. Tworzenie polityki wzbogacania
Teraz nadszedł czas na przygotowanie wzbogacania danych. Pierwszym krokiem jest stworzenie polityki wzbogacania, używając poniższego polecenia z ciałem żądania:
PUT /_enrich/policy/enrich-statistics-policy
{
"match": {
"indices": [
"db-statistics"
],
"match_field": "driverId",
"enrich_fields": [
"races",
"wins",
"titles"
]
}
}
Polityka wzbogacania dla indeksów określonych w ciele zapytania może zostać stworzona tylko wtedy, gdy mapowanie jest już znane. Może być ono zaktualizowane przed jakimkolwiek zaindeksowaniem danych, lub Elasticsearch utworzy domyślne mapowanie, gdy dane zostaną zaindeksowane po raz pierwszy.
2. Wykonanie polityki wzbogacania
Kolejnym krokiem, po utworzeniu polityki, jest jej wykonanie. Wykonanie realizowane jest za pomocą poniższego zapytania:
PUT /_enrich/policy/enrich-statistics-policy/_execute
Po wykonaniu zapytania, powinno pojawić się następujące odpowiedź, wskazująca, że operacja zakończyła się sukcesem:
{
"status": {
"phase": "COMPLETE"
}
}
3. Pobranie polityki wzbogacania
Informacje o polityce wzbogacania mogą być pobrane za pomocą nazwy polityki, używając poniższego zapytania:
GET /_enrich/policy/enrich-statistics-policy
4. Usunięcie polityki wzbogacania
Po utworzeniu polityki wzbogacania nie można jej zaktualizować ani zmodyfikować. Jedynym sposobem wprowadzenia nowej polityki jest usunięcie starej. Jednak przed jej usunięciem należy usunąć również pipeline, który ją wykorzystuje (patrz rozdział „Ingest API – 3. Usuwanie pipeline”).
Politykę wzbogacania można usunąć za pomocą poniższego zapytania:
DELETE /_enrich/policy/enrich-statistics-policy
Ingest pipeline
Ingest API służy do zarządzania zadaniami i zasobami związanymi z pipeline’ami oraz procesorami.
1. Tworzenie pipeline
Po utworzeniu polityki wzbogacania kolejnym krokiem jest stworzenie pipeline’a, który będzie używany podczas indeksowania nowych dokumentów. Zapytanie zawiera nazwę pipeline’a driver-enrichment-pipeline oraz konfigurację w ciele żądania, jak pokazano poniżej:
PUT /_ingest/pipeline/driver-enrichment-pipeline
{
"description": "Enrich drivers statistics information",
"processors": [
{
"enrich": {
"policy_name": "enrich-statistics-policy",
"field": "driverId",
"target_field": "statistics"
}
},
{
"remove": {
"field": "statistics.driverId"
}
}
]
}
Ta zmiana wchodzi w życie natychmiast po jej zastosowaniu.
2. Pobieranie konfiguracji pipeline
Konfigurację pipeline dla wskazanej nazwy pipeline można sprawdzić, używając poniższego zapytania:
GET /_ingest/pipeline/driver-enrichment-pipeline
3. Usunięcie pipeline
Aby usunąć pipeline, wystarczy wysłać następujące zapytanie z określoną nazwą pipeline:
DELETE /_ingest/pipeline/driver-enrichment-pipeline
Document API
Document API służy do realizowania podstawowych operacji CRUD (tworzenie, odczyt, aktualizacja, usuwanie) na dokumentach. Artykuł ten koncentruje się jedynie na indeksowaniu dokumentów.
1. Indeksowanie dokumentów
Pierwsza część danych potrzebnych do zakończenia zadania to statystyki. Zapytanie typu bulk, zawierające dane w wymaganym formacie, wygląda następująco:
POST /db-statistics/_bulk
{ "index": {}}
{"driverId": "alguersuari", "races": 46, "wins": 0, "titles": 0}
{ "index": {}}
{"driverId": "alonso", "races": 336, "wins": 32, "titles": 2}
{ "index": {}}
{"driverId": "rosa", "races": 105, "wins": 0, "titles": 0}
{ "index": {}}
{"driverId": "glock", "races": 94, "wins": 0, "titles": 0}
{ "index": {}}
{"driverId": "heidfeld", "races": 183, "wins": 0, "titles": 0 }
{ "index": {}}
{"driverId": "hulkenberg", "races": 181, "wins": 0, "titles": 0}
{ "index": {}}
{"driverId": "rosberg", "races": 206, "wins": 23, "titles": 1}
{ "index": {}}
{"driverId": "michael_schumacher", "races": 308, "wins": 91, "titles": 7}
{ "index": {}}
{"driverId": "sutil", "races": 128, "wins": 0, "titles": 0}
{ "index": {}}
{"driverId": "vettel", "races": 279, "wins": 53, "titles": 4 }
{ "index": {}}
{"driverId": "sainz", "races": 140, "wins": 0, "titles": 0}
{ "index": {}}
{"driverId": "wehrlein", "races": 39, "wins": 0, "titles": 0}
{ "index": {}}
{"driverId": "mick_schumacher", "races": 22, "wins": 0, "titles": 0}
2. Indeksowanie dokumentów z użyciem pipeline
Następnie dane driverow mogą zostać zaindeksowane z użyciem pipeline wzbogacania. Jedyna różnica w zapytaniu to dodatkowy parametr pipeline, jak pokazano poniżej. Dla potrzeb artykułu tylko 13 dokumentów jest wstawianych.
POST /db-enriched-drivers/_bulk?pipeline=driver-enrichment-pipeline
{ "index": {}}
{"driverId": "alguersuari", "code": "ALG", "givenName": "Jaime", "familyName": "Alguersuari", "dateOfBirth": "1990-03-23", "nationality": "Spanish", "active": false}
{ "index": {}}
{"driverId": "alonso", "permanentNumber": "14", "code": "ALO", "givenName": "Fernando", "familyName": "Alonso", "dateOfBirth": "1981-07-29", "nationality": "Spanish", "active": true}
{ "index": {}}
{"driverId": "rosa", "code": "DLR", "givenName": "Pedro", "familyName": "de la Rosa", "dateOfBirth": "1971-02-24", "nationality": "Spanish", "active": false}
{ "index": {}}
{"driverId": "glock", "code": "GLO", "givenName": "Timo", "familyName": "Glock", "dateOfBirth": "1982-03-18", "nationality": "German", "active": false}
{ "index": {}}
{"driverId": "heidfeld", "code": "HEI", "givenName": "Nick", "familyName": "Heidfeld", "dateOfBirth": "1977-05-10", "nationality": "German", "active": false}
{ "index": {}}
{"driverId": "hulkenberg", "permanentNumber": "27", "code": "HUL", "givenName": "Nico", "familyName": "HĂźlkenberg", "dateOfBirth": "1987-08-19", "nationality": "German", "active": false}
{ "index": {}}
{"driverId": "rosberg", "permanentNumber": "6", "code": "ROS", "givenName": "Nico", "familyName": "Rosberg", "dateOfBirth": "1985-06-27", "nationality": "German", "active": false}
{ "index": {}}
{"driverId": "michael_schumacher", "code": "MSC", "givenName": "Michael", "familyName": "Schumacher", "dateOfBirth": "1969-01-03", "nationality": "German", "active": false}
{ "index": {}}
{"driverId": "sutil", "permanentNumber": "99", "code": "SUT", "givenName": "Adrian", "familyName": "Sutil", "dateOfBirth": "1983-01-11", "nationality": "German", "active": false}
{ "index": {}}
{"driverId": "vettel", "permanentNumber": "5", "code": "VET", "givenName": "Sebastian", "familyName": "Vettel", "dateOfBirth": "1987-07-03", "nationality": "German", "active": true}
{ "index": {}}
{"driverId": "sainz", "permanentNumber": "55", "code": "SAI", "givenName": "Carlos", "familyName": "Sainz", "dateOfBirth": "1994-09-01", "nationality": "Spanish", "active": true}
{ "index": {}}
{"driverId": "wehrlein", "permanentNumber": "94", "code": "WEH", "givenName": "Pascal", "familyName": "Wehrlein", "dateOfBirth": "1994-10-18", "nationality": "German", "active": false}
{ "index": {}}
{"driverId": "mick_schumacher", "permanentNumber": "47", "code": "MSC"
W wyniku wykonania zapytania otrzymano następującą odpowiedź w Postmanie:

Search API
Search API służy do wyszukiwania i agregowania danych przechowywanych w indeksach Elasticsearch.
1. Wyszukiwanie za pomocą zapytań
Elasticsearch udostępnia bogaty, elastyczny język zapytań o nazwie query DSL, który pozwala na tworzenie bardziej skomplikowanych i zaawansowanych zapytań. Język zapytań (DSL) jest określany za pomocą ciała żądania w formacie JSON.
Poniższe zapytanie zwraca kierowcę, który:
– jest Niemcem,
– jest wciąż aktywny,
– wygrał przynajmniej jeden tytuł.
GET /db-enriched-drivers/_search
{
"query": {
"bool": {
"filter": [
{
"term": {
"nationality": "german"
}
},
{
"term": {
"active": "true"
}
},
{
"range": {
"statistics.titles": {
"gte": 1
}
}
}
]
}
}
}
W rezultacie otrzymano następujący wynik:

Ten fragment pokazuje jedynie, jak budowane są zapytania. Mogą być bardziej skomplikowane i zagnieżdżone.
2. Wyszukiwanie z agregacjami
Agregacje są dodawane do zapytania wyszukiwania w sposób podobny do zapytań. Poniższy fragment kodu pokazuje, jak są one tworzone. Główna agregacja „byNationality” zawiera cztery podagregacje, które odzwierciedlają to, co zostało wykonane w poprzednim artykule za pomocą Java API.
{
"aggs": {
"byNationality": {
"terms": {
"field": "nationality"
},
"aggs": {
"totalWins": {
"sum": {
"field": "statistics.wins"
}
},
"totalTitles": {
"sum": {
"field": "statistics.titles"
}
},
"byHits": {
"top_hits": {
"_source": {
"includes": [
"driverId",
"givenName",
"familyName"
]
},
"size": 100
}
},
"avgRaces": {
"avg": {
"field": "statistics.races"
}
}
}
}
}
}
Zapytania i agregacje mogą być łączone w jednym żądaniu wyszukiwania, aby tworzyć bardziej zaawansowane zapytania, spełniające wymagania projektu.
Podsumowanie
Ten artykuł przedstawia Elasticsearch REST API, które można wykorzystać do komunikacji z Elasticsearch w praktyce za pomocą ulubionego klienta webowego, wykonując te same operacje, co w poprzednich artykułach z użyciem Java API.
Poznaj mageek of j‑labs i daj się zadziwić, jak może wyglądać praca z j‑People!
Skontaktuj się z nami


