Bazy NoSQL WB@NOSQL

Wyszukiwanie z ElasticSearch

[John Cage]

I can't understand why people are frightened of new ideas. I'm frightened of the old ones.

— John Cage (1912–1992)

Zaczynamy od lektury What's Wrong with SQL search.

Książka:

Podręczne linki do ElasticSearch:

Misc tools:

Pobieramy ostatnią stabilną wersję Elasticsearch i instalujemy ją na swoim komputerze.

ElasticSearch driver dla języka Ruby, v1.0.6:

Gem elasticsearch-transport korzysta z gemu faraday.

Przykładowa instalacja z paczki

Pobieramy ostatnie wersje ElasticSearch i Kibana ze strony Get Started… i postępujemy według instrukcji.

W katalogu config podmieniamy node name, np. na:

elasticsearch.yml
node.name: "John Cage"

I uruchamiamy elasticsearch.

Domyślnie ElasticSearch nasłuchuje na porcie 9200, a Kibana na 5601:

http://localhost:9200/?pretty
http://localhost:5601 # przechodzimy do Console w zakładce DevTools

ElasticSearch zwraca wynik wyszukiwania w formacie JSON. Dlatego wygodnie jest już teraz zainstalować dodatek do Firefoks o nazwie JSONView.

Opcjonalnie instalujemy elasticsearch-head – a_web front end for an elastic search cluster_.

The usual purpose of a full-text search engine is to return a small number of documents matching your query.

Your data, Your search

…czyli kilka przykładów ze strony Your Data, Your Search.

Podstawowe terminy to: index i type.

Interpretacja URI w zapytaniach kierowanych do ElasticSearch:

http://localhost:9200/⟨index⟩/⟨type⟩/...

Częścią Elasticsearch jest wyszukiwarka Apache Lucene. Składnia zapytań Lucene jest opisana w dokumencie Query Parser Syntax.

Tworzenie i usuwanie indeksu o nazwie tweets:

curl -XPUT localhost:9200/tweets
curl -XDELETE localhost:9200/tweets

Field names with the same name across types are highly recommended to have the same type and same mapping characteristics (analysis settings for example).

index & type w przykładach

Przykładowy dokument:

book.json
{
  "isbn": "0812504321",
  "name": "Call of the Wild",
  "author": {
     "first_name": "Jack",
     "last_name": "London"
   },
   "pages": 128,
   "tags": ["fiction", "children"]
}

Dodajemy ten dokument do /amazon/books (/index/type):

curl -XPUT http://localhost:9200/amazon/books/0812504321 -d @book.json
  {"ok":true,"_index":"amazon","_type":"books","_id":"0812504321","_version":1}

Przykładowe zapytanie (w query string):

curl -s 'http://localhost:9200/amazon/books/_search?pretty=true&q=author.first_name:Jack'

Jeszcze jeden dokument:

cd.json
{
   "asin": "B00192IV0O",
   "name": "THE E.N.D. (Energy Never Dies)",
   "artist": "Black Eyed Peas",
   "label": "Interscope",
   "release_date": "2009-06-09",
   "tags": ["hip-hop", "pop-rap"]
}

Ten dokument dodajemy do /amazon/cds (/index/type):

curl -XPUT http://localhost:9200/amazon/cds/B00192IV0O -d @cd.json
  {"ok":true,"_index":"amazon","_type":"cds","_id":"B00192IV0O","_version":1}

Przykładowe zapytanie:

curl -s 'http://localhost:9200/_search?pretty=true&q=label:Interscope'

albo, korzystając z programu jq:

curl -s 'http://localhost:9200/_search?q=label:Interscope' | jq .

Wyszukiwanie po wszystkich typach w indeksie /amazon:

curl -s 'http://localhost:9200/amazon/_search?q=name:energy' | jq .

Wyszukiwanie w indeksie /amazon po kilku typach:

curl -s 'http://localhost:9200/amazon/books,cds/_search&q=name:energy' | jq .

Na koniec posprzątamy po sobie, czyli usuniemy oba dodane dokumenty. W tym celu wystarczy usunąć indeks /amazon:

curl -XDELETE 'http://localhost:9200/amazon'

Można też usunąć wszystkie dokumenty (zalecana jest ostrożność):

curl -XDELETE 'http://localhost:9200/_all'

Na koniec zapytamy klaster ElasticSearch o zdrowie:

curl -s 'http://localhost:9200/_cluster/health' | jq .
curl -s 'http://localhost:9200/_cluster/health?format=yaml'  # YAML, v1.4+

Czy Elasticsearch ma REST API?

Korzystamy z JSON Query Language

Najpierw zapiszemy te dokumenty w ElasticSearch:

curl -XPUT 'http://localhost:9200/twitter/users/kimchy' -d '
{
   "name": "Shay Banon"
}'

curl -XPUT 'http://localhost:9200/twitter/tweets/1' -d '
{
   "user": "kimchy",
   "postDate": "2009-11-15T13:12:00",
   "message": "Trying out Elastic Search, so far so good?"
}'

curl -XPUT 'http://localhost:9200/twitter/tweets/2' -d '
{
   "user": "kimchy",
   "postDate": "2009-11-15T14:12:12",
   "message": "Another tweet, will it be indexed?"
}'

Sprawdzamy, co zostało dodane:

curl 'http://localhost:9200/twitter/users/kimchy?pretty=true'
curl 'http://localhost:9200/twitter/tweets/1?pretty=true'
curl 'http://localhost:9200/twitter/tweets/2?pretty=true'

Teraz możemy odpytywać indeks /twitter korzystając JSON query language:

curl 'http://localhost:9200/twitter/tweets/_search?pretty=true' -d '
{
  "query": {
    "match": { "user": "kimchy" }
  }
}'
curl 'http://localhost:9200/twitter/tweets/_search?pretty=true' -d '
{
   "query": {
     "term": { "user": "kimchy" }
   }
}'

Jaka jest różnica między wyszukiwaniem z match (w poprzednich wersjach zamiast match używano text) a z term?

Sprawdzamy ile jest dokumentów w indeksie twitter:

curl http://localhost:9200/twitter/_count

Wyciągamy wszystkie dokumenty z indeksu twitter:

curl 'http://localhost:9200/twitter/_search?pretty=true' -d '
{
    "query": {
        "matchAll": {}
    }
}'

Albo – dokumenty typu users z indeksu twitter:

curl -XGET 'http://localhost:9200/twitter/users/_search?pretty=true' -d '
{
  "query": {
    "matchAll": {}
  }
}'

Indeksy Multi Tenant

Tenant to najemca, dzierżawca, a Multi Tenant to…?

Czy poniższy przykład pozwala zrozumieć sens multi tenancy?

curl -XPUT 'http://localhost:9200/bilbo/info/1' -d '{ "name": "Bilbo Baggins" }'
curl -XPUT 'http://localhost:9200/frodo/info/1' -d '{ "name": "Frodo Baggins" }'

curl -XPUT 'http://localhost:9200/bilbo/tweets/1' -d '
{
    "user": "bilbo",
    "postDate": "2009-11-15T13:12:00",
    "message": "Trying out Elastic Search, so far so good?"
}'
curl -XPUT 'http://localhost:9200/frodo/tweets/1' -d '
{
    "user": "frodo",
    "postDate": "2009-11-15T14:12:12",
    "message": "Another tweet, will it be indexed?"
}'

Wyszukiwanie „multi”, po kilku indeksach:

curl -XGET 'http://localhost:9200/bilbo,frodo/_search?pretty=true' -d '
{
    "query": {
        "matchAll": {}
    }
}'

ES cluster health

Od czasu do czasu powinniśmy zapytać się ES o zdrowie:

curl -s http://localhost:9200/_cluster/health

Dlaczego?