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,317