ElasticSearch
Marcin
Lewandowski



ElasticSearch
Marcin
Lewandowski



Marcin Lewandowski
- programista z ponad 15 letnim doświadczeniem,
- tworzę i rozwijam systemy dla logistyki,
- prowadzę bloga czterytygodnie.pl







Uczestnicy
- Imię i nazwisko
- Jaki jest dla mnie cel szkolenia ?
- Czy udało mi się wypełnić Kwestionariusz Oczekiwań przed szkoleniem ?
- Gdzie i w jaki sposób będę wykorzystywać wiedzę ze szkolenia ?
- Co aktualnie wiem o temacie szkolenia ?
- Jakie wykorzystuję oprogramowanie związane z tematem szkolenia ?

Marcin
Lewandowski


Informacje organizacyjne

Marcin
Lewandowski

09:00 do 09:15 - Rozpoczęcie dnia, sprawy organizacyjne
09:15 do 10:45 - Blok szkoleniowy
10:45 do 11.00 - Przerwa kawowa ( 15 min. )
11:00 do 13:00 - Blok szkoleniowy
13:00 do 13:45 - Przerwa obiadowa ( 45 min. )
13:45 do 14:45 - Blok szkoleniowy
14:45 do 15:00 - Przerwa kawowa ( 15 min. )
15:00 do 16:00 - Blok szkoleniowy
16:00 do 17:00 - Praca indywidualna uczestników

Marcin
Lewandowski

Plan szkolenia
1. Introduction to Elasticsearch
2. Writing Search Queries
3. Performing Text Analysis
4. Defining Mappings
5. Expanding Your Searches
6. The Distributed Model
7. Manipulating Search Results
8. Performing Aggregations
9. Handling Data Relationships
10. Summary and Conclusion


Wprowadzenie do ElasticSearch

Wprowadzenie do ElasticSearch
- Silnik wyszukiwania pełnotekstowego oparty o bazę dokumentów,
- Wykorzystuje Apache Lucene,
- REST API,
- Dokumenty w formacie JSON,
- Schemat indeksu budowany dynamicznie,
- Wysoki poziom dostępności i skalowalności rozwiązania

Wprowadzenie do ElasticSearch




ELK
Elastic Stack
Elasticsearch
Logstash
Kibana
Beats

X Pack

Elastic cloud

Kibana

Wprowadzenie do ElasticSearch
- Przeglądanie danych,
- Wizualizacja danych
- Dashboard,
- Mapy,
- Wykresy,
- Raporty ( Lens )
- SIEM ( dla działów bezpieczeństwa )
- Zarządzanie i monitorowanie klastrem
- Alerty,
- Kontrola dostępu,
- AL ( Machine Learning )

Logstash

Wprowadzenie do ElasticSearch
- Narzędzie do zasilania danymi ElasticSearch,
- Możliwe podpięcie rozwiązania pod wiele źródeł danych,
- Transformacja danych wejściowych na określony format dzięki rozbudowanej liście filtrów,
- Elastyczne rozwiązanie dzięki bogatej liście pluginów,
- Skalowanie horyzontalne + kolejki

Logstash

Wprowadzenie do ElasticSearch






Logstash

Wprowadzenie do ElasticSearch








X-Pack

Wprowadzenie do ElasticSearch

Odpowiedzialny za bezpieczeństwo danych.
- W podstawowej wersji mamy możliwość zabezpieczenia klastra w oparciu o użytkowników i role
X-Pack

Wprowadzenie do ElasticSearch

Alternatywy
- Readonly REST - https://readonlyrest.com
- Search Guard - https://search-guard.com
- Reverse proxy - https://logz.io/blog/securing-elk-nginx/
Beats

Wprowadzenie do ElasticSearch

Lekka aplikacja napisana w Go służąca do przesyłania danych specjalny przygotowanych pod ElasticSearch.
Najważniejsze cech:
- lekka aplikacja generująca znikome obciążenie na serwerze,
- gotowe moduły dla najczęstszych rozwiązań znajdujących się na serwerach np. Nginx, Apache, Docker, RabbitMQ, Kafka, MySQL, MariaDB
Beats

Wprowadzenie do ElasticSearch

Dostępne Beats
- Filebeat - dostarcza logi,
- Metricbeat - dostarcza metryki,
- Heartbeat - monitoruje uptime serwisów
- Packetbeat - informacje o sieci (netflow)
- Auditbeat - informacje związane z kwestiami bezpieczeństwa (Linux Audit Framework)
- Winlogbeat - dostarcza informacje o zdarzeniach z systemu Windows
Architektura
ElasticSearch

Architektura
SERWER
( cluster, node, shard, replica )
DANE
( index, type, document )
Architektura
ElasticSearch

Architektura serwera

NODE (węzeł)
CLUSTER (klaster)


SHARD / REPLICA
zbiór jednego lub więcej węzłów
pojedyncza instalacja serwera

Architektura
ElasticSearch
Architektura danych
do wersji 7
INDEX (indeks)
TYPE (typ)
sposób grupowania dokumentów
kolekcja dokumentów
DOCUMENT (dokument)
podstawowa jednostka indeksowania

DATABASE (baza danych)
TABLE (tabela)
RECORD (rekord / wiersz)


Architektura danych
po wersji 7.x
INDEX (indeks)
kolekcja dokumentów
DOCUMENT (dokument)
podstawowa jednostka indeksowania

TABLE (tabela)
RECORD (rekord / wiersz)


Przygotowanie
środowiska


Linux
Instalacja serwera
Zalogowanie na administratora
sudo su
Import klucza PGP
wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo gpg --dearmor -o /usr/share/keyrings/elasticsearch-keyring.gpg
Instalacja pakietu apt-transport-https
sudo apt-get install apt-transport-https
Dodanie repozytorium z ElasticSearch
echo "deb [signed-by=/usr/share/keyrings/elasticsearch-keyring.gpg] https://artifacts.elastic.co/packages/7.x/apt stable main" | sudo tee /etc/apt/sources.list.d/elastic-7.x.list
Aktualizacja listy pakietów i instalacja Elasticsearch
sudo apt-get update && sudo apt-get install elasticsearch

Linux
Instalacja serwera
Sprawdzamy czy serwis wystartował
systemctl status elasticsearch.service
Startujemy serwis
systemctl start elasticsearch.service

Linux
Instalacja serwera
Instalacja Kibany
sudo apt-get install kibana
Dodajemy serwis do autostartu
systemctl enable kibana
Kibana
Startujemy serwis
systemctl start kibana
Sprawdzamy czy mamy dostęp do Kibany pod adresem
localhost:5601

Linux
Instalacja serwera
Docker
Instalacja Docker
apt-get install docker.io
Instalacja Docker Compose
apt-get install docker-compose
Wymagania:
- Docker, dostarcza kontenery,
- Docker Compose, pozwala stworzyć plik z konfiguracją środowiska

Linux
Instalacja serwera
Wyszukujemy odpowiedni obraz na Docker Hub np.
Docker
Startujemy kontener
docker run -d -p 9201:9200 -p 5602:5601 nshou/elasticsearch-kibana
Sprawdzamy czy mamy dostęp do Kibany pod adresem
localhost:5602
Sprawdzamy czy kontener został uruchomiony
docker ps

Linux
Instalacja serwera
docker-compose.yml
Plik z konfiguracją środowiska testowego
version: '3'
services:
es:
image: nshou/elasticsearch-kibana
ports:
- "9201:9200"
- "5602:5601"
- wykorzystujemy obraz nshou/elasticsearch-kibana, który ma dodaną Kibanę,
- przekierowujemy porty,
- 9200 - ElasticSearch,
- 5601 - Kibana

Linux
Instalacja serwera
docker-compose.yml
Uruchomienie środowiska
docker-compose up
Uruchomienie środowiska w tle
docker-compose up -d
Sprawdzenie uruchomionych kontenerów
docker ps
Zatrzymanie środowiska
ctrl + c
Zatrzymanie środowiska
docker-compose down
Indeks

Indeks
- zbiór wszystkich dokumentów
- REST API
- domyślnie zawiera 5 shardów i 5 replik
- odwrócony indeks

Indeks odwrócony


Zadanie
PUT shop
Dodajemy indeks
Odpowiedź
{
"acknowledged": true,
"shards_acknowledged": true,
"index": "shop"
}
Kibana
CURL
curl -XPUT 'localhost:9200/shop'

Błędy przy dodawaniu indeksu
Indeks istnieje
{
"error": {
"root_cause": [
{
"type": "resource_already_exists_exception",
"reason": "index [shop/BlQB1sKYTA6sV6KOpCp4cw] already exists",
"index_uuid": "BlQB1sKYTA6sV6KOpCp4cw",
"index": "shop"
}
],
"type": "resource_already_exists_exception",
"reason": "index [shop/BlQB1sKYTA6sV6KOpCp4cw] already exists",
"index_uuid": "BlQB1sKYTA6sV6KOpCp4cw",
"index": "shop"
},
"status": 400
}
Składnia
{
"error": "Incorrect HTTP method for uri [/shop] and method [POST], allowed: [GET, HEAD, DELETE, PUT]",
"status": 405
}

Zadanie
Sprawdzamy listę indeksów
Kibana
GET _stats
Odpowiedź
{
"_shards": {
...
},
"_all": {
...
},
"indices": {
"shop": {
...
}
}
}
CURL
curl -XGET 'localhost:9200/_stats?pretty'

Zadanie
Usuwanie indeksu
Kibana
DELETE shop
Odpowiedź
{
"acknowledged": true
}
CURL
curl -XDELETE 'localhost:9200/shop?pretty'
Lista indeksów
{
"_shards": {
...
},
"_all": {
...
},
"indices": {}
}

Indeks nie istnieje
{
"error": {
"root_cause": [
{
"type": "index_not_found_exception",
"reason": "no such index",
"resource.type": "index_or_alias",
"resource.id": "shop",
"index_uuid": "_na_",
"index": "shop"
}
],
"type": "index_not_found_exception",
"reason": "no such index",
"resource.type": "index_or_alias",
"resource.id": "shop",
"index_uuid": "_na_",
"index": "shop"
},
"status": 404
}
Błędy przy usuwaniu indeksu

Typy

Typy

- REST API
- grupowanie dokumentów w ramach indeksu
ElasticSearch 5
ElasticSearch 6
wielu typów w ramach jednego indeksu
tylko jeden typ w indeksie

ElasticSearch 7
rezygnacja z typów
Zadanie
POST shop/products
{
}
Dodajemy nowy typ
Kibana
curl -XPOST 'localhost:9200/shop/products?pretty' -d '{}'
CURL
{
"_index": "shop",
"_type": "products",
"_id": "9nCx-GYB4OAq-pq-3A1z",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1
}
Odpowiedź
Mapping

Mapping
określa typy pól w dokumentach



Zadanie
GET shop/_mapping
Sprawdzamy mapping
Kibana
curl -XGET 'localhost:9200/shop/_mapping?pretty'
CURL
{
"shop" : {
"mappings" : {
}
}
}
Odpowiedź
Generowanie Mappingu
dwie metody generowania
automatyczne
przez użytkownika
mapping generowany na podstawie przesyłanych dokumentów
mapping określa użytkownik przesyłając schemat mappingu
Zadanie
Dodajemy dokument do indeksu
Kibana
POST shop
{
"name": "Xiaomi Redmi 4X",
"price": 1200,
"category": "smartfon",
"creation_date": "2018-01-30"
}
Odpowiedź
{
"_index": "shop",
"_type": "products",
"_id": "BXDj-GYB4OAq-pq-SQ5Y",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1
}
Zadanie
Dodajemy dokument do indeksu o określonym identyfikatorze
POST shop/1
{
"name": "Xiaomi Redmi 4X",
"price": 1200,
"category": "smartfon",
"creation_date": "2018-01-30"
}
Odpowiedź
{
"_index": "shop",
"_type": "products",
"_id": "1",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1
}
Zadanie
Sprawdzamy automatycznie wygenerowany mapping
Kibana
GET shop/_mapping
"category": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"creation_date": {
"type": "date"
},
"name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"price": {
"type": "long"
}
POST shop
{
"name": "Xiaomi Redmi 4X",
"price": 1200,
"category": "smartfon",
"creation_date": "2018-01-30"
}
Zadanie
Dodajemy produkt z typem float
Kibana
POST shop
{
"name": "Xiaomi Redmi 4X",
"price": 1199.99,
"category": "smartfon",
"creation_date": "2018-01-30"
}
GET shop/_mapping
Sprawdzamy czy zmienił się mapping
...
"price": {
"type": "long"
}
Odpowiedź
Zadanie
Dodajemy produkt z nowym polem float
POST shop
{
"name": "Xiaomi Redmi 4X",
"price": 1500.00,
"promotion": 1199.99,
"category": "smartfon",
"creation_date": "2018-01-30"
}
GET shop/_mapping
Sprawdzamy czy zmienił się mapping
...
"promotion": {
"type": "float"
}
Odpowiedź
Ręczne definiowanie mappingu
- lepsza kontrola nad typami
- definiujemy w momencie tworzenia indeksu
PUT shop
{
"mappings": {
"properties": {
... mapping ...
}
}
}
Aktualizacja mappingu
- aktualizacja istniejących pól jest niemożliwe
- dodawanie definicji dla nowych pól jest dozwolone
- dozwolone są operacje:
- dodania parametrów do pola typu Object datatype
- dodanie parametru ignore_above
- dodanie multi-fields do istniejącego pola
Zadanie
Definiujemy mapping
Usuwamy indeks
DELETE shop
PUT shop
{
"mappings": {
"properties": {
"category": {
"type": "text"
},
"creation_date": {
"type": "date"
},
"name": {
"type": "text"
},
"price": {
"type": "double"
}
}
}
}
Tworzymy indeks
Sprawdzamy mapping
GET shop/_mapping
"shop": {
"mappings": {
"properties": {
"category": {
"type": "text"
},
"creation_date": {
"type": "date"
},
"name": {
"type": "text"
},
"price": {
"type": "double"
}
}
}
}
Obiekty zagnieżdżone
( nested )
"manufacturer": {
"type": "nested",
"properties": {
... lista pól ...
}
}
- pole przechowujące obiekt JSON lub tablicę obiektów
- ukryte dokumenty
- specyficzny sposób wyszukiwania
Definicja pola nested
Zadanie
Dodajemy pole typu nested do indeksu
PUT shop/_mapping
{
"properties": {
"manufacturer": {
"properties": {
"id": {
"type": "integer",
"store": true,
"index": true
},
"name": {
"type": "text"
}
}
}
}
}
Aktualizujemy mapping
GET shop/_mapping
{
"shop": {
"mappings": {
"properties": {
"category": {
"type": "text"
},
"creation_date": {
"type": "date"
},
"manufacturer": {
"properties": {
"id": {
"type": "integer",
"store": true
},
"name": {
"type": "text"
}
}
},
"name": {
"type": "text"
},
"price": {
"type": "double"
}
}
}
}
}
Sprawdzamy modyfikacje
Dokumenty

Dokumenty
Proces dodawania do indeksu


analyzer: {
"char_filter": ["html_strip"],
"tokenizer": "standard",
"filter": ["lowercase"]
}
Testowanie poszczególnych elementów
GET /_analyze
{
"text": ["Xiaomi <strong>Redmi</strong> 4X"]
}
Do testów poszczególnych elementów używamy endpoint-u _analyze

Dokumenty
char_filter
GET /_analyze
{
"char_filter": [
"html_strip"
],
"text": ["Xiaomi <strong>Redmi</strong> 4X"]
}


Dokumenty
Filtry znaków
char_filter - HTML strip character filter
PUT test_char_filter
{
"settings": {
"analysis": {
"char_filter": {
"accept_strong": {
"type": "html_strip",
"escaped_tags": [
"strong"
]
}
}
}
}
}

Możliwa jest tworzenie własnych ustawień dla filtrów znaków.
GET /test_char_filter/_analyze
{
"char_filter": [
"accept_strong"
],
"text": ["Xiaomi <strong>Redmi</strong> 4X"]
}
Filtry znaków
mapping - Mapping Character Filter

Filtr mapowania znaków pozwala przypisać określonym znakom odpowiedniki.
GET /_analyze
{
"char_filter": [
{
"type": "mapping",
"mappings": [
"1 => jeden",
"2 => dwa"
]
}
],
"text": ["Akceptowane cyfry to: 1 lub 2"]
}
Zamiast wpisywania całego mapping-u ręcznie, możliwe jest zdefiniowanie go w pliku i podanie ścieżki do pliku. Robimy to w parametrze: mappings_path
Filtry znaków
mapping - Mapping Character Filter

Filtr mapowania znaków pozwala przypisać określonym znakom odpowiedniki.
GET /_analyze
{
"char_filter": [
{
"type": "mapping",
"mappings": [
"1 => jeden",
"2 => dwa"
]
}
],
"text": ["Akceptowane cyfry to: 1 lub 2"]
}
Zamiast wpisywania całego mapping-u ręcznie, możliwe jest zdefiniowanie go w pliku i podanie ścieżki do pliku. Robimy to w parametrze: mappings_path
Filtry znaków
pattern_replace - Pattern Replace Character Filter

Filtr wyrażeń regularnych.
GET /_analyze
{
"char_filter": [
{
"type": "pattern_replace",
"pattern": "(\\d+)",
"replacement": "$1 (cyfra)"
}
],
"text": ["Akceptowane cyfry to: 1 lub 2"]
}
Tokenizer
- najważniejszy element analizera
- odpowiedzialny za podział tekstu na tokeny

- korzystamy tylko z wbudowanych tokenizerów

Tokenizer

Dostępne tokenizery



Tokenizer
standard
GET /_analyze
{
"tokenizer": "standard",
"text": "Xiaomi Redmi 4X"
}
{
"tokens": [
{
"token": "Xiaomi",
"start_offset": 0,
"end_offset": 6,
"type": "<ALPHANUM>",
"position": 0
},
{
"token": "Redmi",
"start_offset": 7,
"end_offset": 12,
"type": "<ALPHANUM>",
"position": 1
},
{
"token": "4X",
"start_offset": 13,
"end_offset": 15,
"type": "<ALPHANUM>",
"position": 2
}
]
}
Tokenizer standardowy
Efekt działania

Filtry tokenów




Filtry tokenów

GET /_analyze
{
"tokenizer" : "standard",
"filter" : ["lowercase"],
"text" : "Xiaomi Redmi 4X"
}
lowercase
{
"tokens" : [
{
"token" : "xiaomi",
"start_offset" : 0,
"end_offset" : 6,
"type" : "<ALPHANUM>",
"position" : 0
},
{
"token" : "redmi",
"start_offset" : 7,
"end_offset" : 12,
"type" : "<ALPHANUM>",
"position" : 1
},
{
"token" : "4x",
"start_offset" : 13,
"end_offset" : 15,
"type" : "<ALPHANUM>",
"position" : 2
}
]
}
Standard Tokenizer
Standard Token Filter, Lower Case Token Filter
Lower Case Tokenizer
Whitespace Tokenizer
Pattern Tokenizer
Lower Case Token Filter, Stop Token Filter
Standard Tokenizer
Lower Case Token Filter, ASCII Folding Token Filter, Stop Token Filter, Fingerprint Token Filter
Lower Case Tokenizer
dodaje obsługę stop words
zwraca dane wejściowe jako pojedynczy token
obsługują specyficznie każdy wspierany język

Analizery
Dostępne analizery

Analizery
Dostępne analizery
GET /_analyze
{
"analyzer": "standard",
"text": "Xiaomi Redmi 4X"
}
Analizer standardowy
Tworzymy własny analizer
{
"settings": {
"analysis": {
"analyzer": {
...
}
}
}
}
Struktura
Analizer
"my_analyzer": {
"type": "custom",
"char_filter": [
"html_strip"
],
"tokenizer": "standard",
"filter": [
"lowercase"
]
}
PUT shop/_settings
{
"analysis": {
"analyzer": {
"my_analyzer": {
"type": "custom",
"char_filter": ["html_strip"],
"tokenizer": "standard",
"filter": ["lowercase"]
}
}
}
}
POST /shop/_close
POST /shop/_open
Zamykamy indeks
Otwieramy indeks

Analizery
Zadanie
Testujemy stworzony analizer
GET /shop/_analyze
{
"analyzer": "standard",
"text": ["Xiaomi <strong>Redmi</strong> 4X"]
}
GET /shop/_analyze
{
"analyzer": "my_analyzer",
"text": ["Xiaomi <strong>Redmi</strong> 4X"]
}
{
"tokens": [
{
"token": "xiaomi",
"start_offset": 0,
"end_offset": 6,
"type": "<ALPHANUM>",
"position": 0
},
{
"token": "redmi",
"start_offset": 15,
"end_offset": 29,
"type": "<ALPHANUM>",
"position": 1
},
{
"token": "4x",
"start_offset": 30,
"end_offset": 32,
"type": "<ALPHANUM>",
"position": 2
}
]
}
{
"tokens": [
{
"token": "xiaomi",
"start_offset": 0,
"end_offset": 6,
"type": "<ALPHANUM>",
"position": 0
},
{
"token": "strong",
"start_offset": 8,
"end_offset": 14,
"type": "<ALPHANUM>",
"position": 1
},
{
"token": "redmi",
"start_offset": 15,
"end_offset": 20,
"type": "<ALPHANUM>",
"position": 2
},
{
"token": "strong",
"start_offset": 22,
"end_offset": 28,
"type": "<ALPHANUM>",
"position": 3
},
{
"token": "4x",
"start_offset": 30,
"end_offset": 32,
"type": "<ALPHANUM>",
"position": 4
}
]
}

Wyszukiwanie

Rodzaje Wyszukiwania
Precyzyjne
Pełnotekstowe
brak analizy wyszukiwanej frazy
przed rozpoczęciem wyszukiwania fraza jest analizowana

Wyszukiwanie
Mapping
Dane testowe
Otwieramy poniższe linki i zapisujemy jako pliki Ctrl + S.
Nie zmieniamy nazwy plików ;)

Wyszukiwanie
Dane testowe

Wyszukiwanie
Dane testowe
Import indeksu
curl -XPUT 'http://127.0.0.1:9200' -H 'Content-Type: application/json' -d @movies_mapping_v1.txt
Import się nie powiedzie ze względu na pierwszą linię, którą trzeba usunąć PUT movies_v1.
Import danych
curl -XPOST 'http://127.0.0.1:9200/_bulk' -H 'Content-Type: application/json' --data-binary @movies_data-1.txt
Sprawdzamy czy dane znajdują się w indeksie
POST movies_v1/_search
{
...
"hits": {
"total": 20,
"max_score": 1,
"hits": [
{
"_index": "produkty",
"_type": "product",
"_id": "gpPNDGcBIwsD9fejqIT1",
"_score": 1,
"_source": {
"utworzono": "2018-08-23",
"nazwa": "iPad Pro",
"url": "ipad-pro",
"cena": 3500,
"producent": {
"name": "Apple",
"id": 2
},
"kategoria": "Tablety",
"opis": "Zamień komputer..."
}
},
]
}
}

Wyszukiwanie
Rezultat wyszukiwania
Przeszukiwanie określonego pola ( Term )
Wyszukujemy frazę "zielona mila"
Wyszukujemy frazę "zielona"
GET movies_v1/_search
{
"query": {
"term": {
"title": "zielona mila"
}
}
}
GET produkty/_search
{
"query": {
"term": {
"title": "zielona"
}
}
}

Wyszukiwanie
Wyszukiwanie wielu fraz ( Terms )
Wyszukujemy frazę "zielona" lub "mila"
GET produkty/_search
{
"query": {
"terms": {
"nazwa": ["zielona", "mila"]
}
}
}
"hits" : [
{
"_score" : 1.0,
"_source" : {
"title" : "Zielona mila"
}
},
{
"_score" : 1.0,
"_source" : {
"title" : "8 Mila"
}
},
...

Wyszukiwanie
Prefix
Wyszukiwanie tokenów zaczynających się na "zielon"
GET movies_v1/_search
{
"query": {
"prefix": {
"nazwa": "zielon"
}
}
}

Wyszukiwanie
- wyszukiwanie tokenów zaczynających się na określoną wartość,
- zapytanie dość kosztowne dlatego przy częstym wykorzystywaniu na określonym polu warto dodać index_prefixes w mappingu
Ids
GET movies_v1/_search
{
"query": {
"ids": {
"values": [6836, 5573, 1359]
}
}
}

Wyszukiwanie dokumentów po ich identyfikatorze
Wyszukiwanie
Range
GET movies_v1/_search
{
"_source": ["title", "year"],
"query": {
"range": {
"year": {
"gte": 2010,
"lte": 2012
}
}
}
}

Wyszukiwanie dokumentów w ramach zdefiniowanego zakresu.
Wyszukiwanie
GET movies_v1/_search
{
"_source": ["title", "rate"],
"query": {
"range": {
"rate": {
"gte": 8
}
}
}
}
Fuzzy Query
GET movies_v1/_search
{
"_source": ["title"],
"query": {
"fuzzy": {
"title": {
"value": "zielona"
}
}
}
}

Wykorzystuje odległość Levenshteina
- ile kroków należy wykonać, aby przekształcić jedną wartość na drugą np. zmiana, dodanie, usunięcie znaku
- Standardowe ustawienia:
- 2 znaki - musi być zgodność 100%
- 3 - 5 znaków - możliwy jeden krok,
- > 5 znaków - możliwe 2 kroki
Wyszukiwanie
GET movies_v1/_search
{
"_source": ["title"],
"query": {
"term": {
"title": {
"value": "zielona"
}
}
}
}
7 wyników
16 wyników
Wildcard
GET movies_v1/_search
{
"_source": ["title"],
"query": {
"wildcard": {
"title": {
"value": "?arr*"
}
}
}
}

Zapytanie umożliwiające elastyczne wyszukiwanie poprzez zastępowanie znaków znakami specjalnymi.
Znaki specjalne możliwe do wykorzystania:
* - zastępuje wiele znaków
? - zastępuje jeden znak
Wyszukiwanie
Regexp
GET movies_v1/_search
{
"_source": ["title"],
"query": {
"regexp": {
"title": {
"value": "zie.*"
}
}
}
}

Wyszukiwanie oparte o wyrażenia regularne. Zapytanie bardzo zasobożerne i nie jest zalecane używanie tego na produkcji.
Wyszukiwanie
Wyszukiwanie pełnotekstowe

Wyszukiwanie w określonym polu
Wyszukiwanie frazy "zielona mila"
GET movies_v1/_search
{
"_source": ["title"],
"query": {
"match": {
"title": {
"query": "zielona mila"
}
}
}
}

Wyszukiwanie
Match
zmiana operatora na AND
GET movies_v1/_search
{
"_source": ["title"],
"query": {
"match": {
"title": {
"query": "zielona mila",
"operator": "and"
}
}
}
}
Wyszukiwanie w określonej kolejności
Wyszukiwanie frazy "harry potter"
GET movies_v1/_search
{
"_source": ["title"],
"query": {
"match_phrase": {
"title": {
"query": "harry potter"
}
}
}
}

Wyszukiwanie
Match Phrase
dodanie operatora na sloop
GET movies_v1/_search
{
"_source": ["title"],
"query": {
"match_phrase": {
"title": {
"query": "harry sally",
"slop": 1
}
}
}
}
Wyszukiwanie frazy
"harry Hendersons"
GET movies_v1/_search
{
"_source": ["title", "title_org"],
"query": {
"multi_match": {
"fields": [
"title",
"title_org"
],
"query": "harry Hendersons"
}
}
}

Wyszukiwanie
Multi Match
Przeszukiwanie wielu pól jednocześnie.
GET movies_v1/_search
{
"_source": ["title", "title_org"],
"query": {
"multi_match": {
"fields": [
"title^3",
"title_org"
],
"query": "harry Hendersons"
}
}
}
Boost na polu title
GET movies_v1/_search
{
"_source": ["title", "title_org"],
"query": {
"nested": {
"path": "genres",
"query": {
"match": {
"genres.name": "komedia"
}
}
}
}
}

Wyszukiwanie
Nested
Wyszukiwania złożone

Bool
Struktura zapytania
GET produkty/_search
{
"query": {
"bool" : {
"must" : {},
"filter": {},
"must_not" : {},
"should" : {}
}
}
}

Zadanie
Wyszukujemy wszystkie produkty z kategorii "tablety"
bool - must
GET produkty/_search
{
"query": {
"bool": {
"must": {
"match": {
"kategoria": "tablety"
}
}
}
}
}

Zadanie
Wyszukujemy wszystkie produkty z kategorii "tablety" w przedziale cenowym od 1000 do 1500
bool - must
GET produkty/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"kategoria": "tablety"
}
},
{
"range": {
"cena": {
"gte": 1000,
"lte": 1500
}
}
}
]
}
}
}

Zadanie
Wyszukujemy wszystkie produkty z kategorii "tablety" bez wpływu na "_score"
Bool - filter
GET produkty/_search
{
"query": {
"bool": {
"filter": {
"match": {
"kategoria": "tablety"
}
}
}
}
}

Zadanie
Wyszukujemy wszystkie produkty z kategorii "tablety" bez producenta "Apple",
gdzie producent jest polem nested nie włączanym do dokumentu
Bool - must_not ( nested )
GET produkty/_search
{
"query": {
"bool": {
"must": {
"match": {
"kategoria": "tablety"
}
},
"must_not": {
"nested": {
"path": "producent",
"query": {
"match": {
"producent.name": "Apple"
}
}
}
}
}
}
}

Zadanie
Wyszukujemy wszystkie produkty z kategorii "tablety" bez producenta "Apple"
Bool - must_not
GET produkty_producent/_search
{
"query": {
"bool": {
"must": {
"match": {
"kategoria": "tablety"
}
},
"must_not": {
"match": {
"producent.name": "Apple"
}
}
}
}
}

Zadanie
Wyszukujemy wszystkie produkty od producenta "Apple" lub "Samsung"
Bool - should
GET produkty_producent/_search
{
"query": {
"bool": {
"should": [
{
"match": {
"producent.name": "Apple"
}
},
{
"match": {
"producent.name": "Samsung"
}
}
]
}
}
}

Reindeksacja
danych

Reindeksacja danych

POST _reindex?wait_for_completion=false
{
"source": {
"index": "movies_v1"
},
"dest": {
"index": "movies_v2"
}
}
Zakładamy index movies_v2 i dodajemy "index_prefixes": { } w polu title
{
"task" : "a9qwXzi2RG6HwYAmSwp6Hg:47188"
}
GET _tasks/a9qwXzi2RG6HwYAmSwp6Hg:47188
{
"completed" : true,
"task" : {
"node" : "a9qwXzi2RG6HwYAmSwp6Hg",
"id" : 47188,
"type" : "transport",
"action" : "indices:data/write/reindex",
"status" : {
"total" : 18221,
"updated" : 0,
"created" : 18221,
"deleted" : 0,
"batches" : 19,
"version_conflicts" : 0,
"noops" : 0,
"retries" : {
"bulk" : 0,
"search" : 0
},
"throttled_millis" : 0,
"requests_per_second" : -1.0,
"throttled_until_millis" : 0
},
Agregacja
danych

Agregacja
danych

GET movies_v1/_search
{
"_source": ["title"],
"aggs": {
"pogrypowane": {
"terms": {
"field": "type",
"size": 10
}
}
}
}
GET movies_v1/_search
{
"_source": ["title"],
"aggs": {
"pogrypowane": {
"terms": {
"field": "type",
"size": 10
},
"aggs": {
...
}
}
}
}
Budujemy wyszukiwarkę

Dziękuję za uwagę :)

Marcin
Lewandowski

ElasticSearch
By Marcin Lewandowski
ElasticSearch
ElasticSearch
- 1,392