Basics Elasticsearch

Elasticsearch se yon motè rechèch ak json rès api, lè l sèvi avèk Lucene ak ekri nan Java. Yon deskripsyon tout avantaj ki genyen nan motè sa a disponib nan ofisyèl sou sit wèb. Nan sa ki anba a nou pral refere a Elasticsearch kòm ES.

Motè menm jan yo itilize pou rechèch konplèks nan yon baz done dokiman. Pa egzanp, chèche pran an kont mòfoloji lang lan oswa rechèch pa kowòdone geo.

Nan atik sa a mwen pral pale sou Basics yo nan ES lè l sèvi avèk egzanp lan nan Indexing pòs blog. Mwen pral montre w kijan pou filtre, triye ak rechèch dokiman yo.

Pou m pa depann de sistèm operasyon an, mwen pral fè tout demann bay ES lè l sèvi avèk CURL. Genyen tou yon plugin pou google chrome rele sans.

Tèks la gen lyen ki mennen nan dokiman ak lòt sous. Nan fen a gen lyen pou aksè rapid nan dokiman an. Ou ka jwenn definisyon tèm ki pa abitye nan glosè.

Enstalasyon

Pou fè sa, nou bezwen premye Java. Devlopè rekòmande enstale vèsyon Java ki pi nouvo pase Java 8 aktyalizasyon 20 oswa Java 7 aktyalizasyon 55.

Distribisyon ES la disponib nan sit pwomotè. Apre debake achiv la ou bezwen kouri bin/elasticsearch. Disponib tou pakè pou apt ak yum. Genyen imaj ofisyèl pou docker. Plis sou enstalasyon.

Apre enstalasyon ak lansman, ann tcheke fonksyonalite a:

# для удобства запомним адрес в переменную
#export ES_URL=$(docker-machine ip dev):9200
export ES_URL=localhost:9200

curl -X GET $ES_URL

Nou pral resevwa yon bagay tankou sa a:

{
  "name" : "Heimdall",
  "cluster_name" : "elasticsearch",
  "version" : {
    "number" : "2.2.1",
    "build_hash" : "d045fc29d1932bce18b2e65ab8b297fbf6cd41a1",
    "build_timestamp" : "2016-03-09T09:38:54Z",
    "build_snapshot" : false,
    "lucene_version" : "5.4.1"
  },
  "tagline" : "You Know, for Search"
}

Indexing

Ann ajoute yon pòs nan ES:

# Добавим документ c id 1 типа post в индекс blog.
# ?pretty указывает, что вывод должен быть человеко-читаемым.

curl -XPUT "$ES_URL/blog/post/1?pretty" -d'
{
  "title": "Веселые котята",
  "content": "<p>Смешная история про котят<p>",
  "tags": [
    "котята",
    "смешная история"
  ],
  "published_at": "2014-09-12T20:44:42+00:00"
}'

repons sèvè:

{
  "_index" : "blog",
  "_type" : "post",
  "_id" : "1",
  "_version" : 1,
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "created" : false
}

ES otomatikman kreye endèks blog ak di ki kalite poste. Nou ka trase yon analoji kondisyonèl: yon endèks se yon baz done, ak yon kalite se yon tab nan baz done sa a. Chak kalite gen pwòp konplo li - kat, jis tankou yon tab relasyon. Kat yo pwodwi otomatikman lè dokiman an endis:

# Получим mapping всех типов индекса blog
curl -XGET "$ES_URL/blog/_mapping?pretty"

Nan repons sèvè a, mwen te ajoute valè jaden dokiman endis la nan kòmantè yo:

{
  "blog" : {
    "mappings" : {
      "post" : {
        "properties" : {
          /* "content": "<p>Смешная история про котят<p>", */ 
          "content" : {
            "type" : "string"
          },
          /* "published_at": "2014-09-12T20:44:42+00:00" */
          "published_at" : {
            "type" : "date",
            "format" : "strict_date_optional_time||epoch_millis"
          },
          /* "tags": ["котята", "смешная история"] */
          "tags" : {
            "type" : "string"
          },
          /*  "title": "Веселые котята" */
          "title" : {
            "type" : "string"
          }
        }
      }
    }
  }
}

Li vo sonje ke ES pa fè diferans ant yon valè sèl ak yon etalaj de valè. Pou egzanp, jaden tit la tou senpleman gen yon tit, ak jaden tags la gen yon etalaj de fisèl, byenke yo reprezante nan menm fason an nan kat.
Nou pral pale plis sou kat pita.

Demann

Rekipere yon dokiman pa id li:

# извлечем документ с id 1 типа post из индекса blog
curl -XGET "$ES_URL/blog/post/1?pretty"
{
  "_index" : "blog",
  "_type" : "post",
  "_id" : "1",
  "_version" : 1,
  "found" : true,
  "_source" : {
    "title" : "Веселые котята",
    "content" : "<p>Смешная история про котят<p>",
    "tags" : [ "котята", "смешная история" ],
    "published_at" : "2014-09-12T20:44:42+00:00"
  }
}

Nouvo kle parèt nan repons lan: _version и _source. An jeneral, tout kle kòmanse ak _ yo klase kòm ofisyèl.

Kle _version montre vèsyon dokiman an. Li nesesè pou mekanis optimis bloke a travay. Pou egzanp, nou vle chanje yon dokiman ki gen vèsyon 1. Nou soumèt dokiman ki chanje a epi endike ke sa a se yon modifikasyon nan yon dokiman ki gen vèsyon 1. Si yon lòt moun tou edite yon dokiman ak vèsyon 1 epi li soumèt chanjman devan nou, lè sa a ES p ap aksepte chanjman nou yo, paske li estoke dokiman an ak vèsyon 2.

Kle _source gen dokiman ke nou endèks la. ES pa sèvi ak valè sa a pou operasyon rechèch paske Endis yo itilize pou rechèch. Pou ekonomize espas, ES estoke yon dokiman sous konprese. Si nou sèlman bezwen id la, epi yo pa tout dokiman sous la, Lè sa a, nou ka enfim depo sous.

Si nou pa bezwen plis enfòmasyon, nou ka jwenn sèlman sa ki nan _source:

curl -XGET "$ES_URL/blog/post/1/_source?pretty"
{
  "title" : "Веселые котята",
  "content" : "<p>Смешная история про котят<p>",
  "tags" : [ "котята", "смешная история" ],
  "published_at" : "2014-09-12T20:44:42+00:00"
}

Ou kapab tou chwazi sèlman sèten jaden:

# извлечем только поле title
curl -XGET "$ES_URL/blog/post/1?_source=title&pretty"
{
  "_index" : "blog",
  "_type" : "post",
  "_id" : "1",
  "_version" : 1,
  "found" : true,
  "_source" : {
    "title" : "Веселые котята"
  }
}

Ann endèks kèk pòs plis epi kouri demann ki pi konplèks.

curl -XPUT "$ES_URL/blog/post/2" -d'
{
  "title": "Веселые щенки",
  "content": "<p>Смешная история про щенков<p>",
  "tags": [
    "щенки",
    "смешная история"
  ],
  "published_at": "2014-08-12T20:44:42+00:00"
}'
curl -XPUT "$ES_URL/blog/post/3" -d'
{
  "title": "Как у меня появился котенок",
  "content": "<p>Душераздирающая история про бедного котенка с улицы<p>",
  "tags": [
    "котята"
  ],
  "published_at": "2014-07-21T20:44:42+00:00"
}'

Triye

# найдем последний пост по дате публикации и извлечем поля title и published_at
curl -XGET "$ES_URL/blog/post/_search?pretty" -d'
{
  "size": 1,
  "_source": ["title", "published_at"],
  "sort": [{"published_at": "desc"}]
}'
{
  "took" : 8,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "failed" : 0
  },
  "hits" : {
    "total" : 3,
    "max_score" : null,
    "hits" : [ {
      "_index" : "blog",
      "_type" : "post",
      "_id" : "1",
      "_score" : null,
      "_source" : {
        "title" : "Веселые котята",
        "published_at" : "2014-09-12T20:44:42+00:00"
      },
      "sort" : [ 1410554682000 ]
    } ]
  }
}

Nou te chwazi dènye pòs la. size limite kantite dokiman yo dwe bay. total montre kantite total dokiman ki koresponn ak demann lan. sort nan pwodiksyon an gen yon etalaj de nonm antye ki fè klasman. Moun sa yo. dat la te konvèti nan yon nonb antye relatif. Ou ka jwenn plis enfòmasyon sou klasman nan dokiman.

Filtè ak demann

ES depi vèsyon 2 pa fè distenksyon ant filtè ak demann, olye se konsèp nan kontèks prezante.
Yon kontèks rechèch diferan de yon kontèks filtre paske rechèch la jenere yon _score epi li pa nan kachèt. Mwen pral montre w kisa _score ye pita.

Filtre pa dat

Nou itilize demann lan ranje nan kontèks filtre:

# получим посты, опубликованные 1ого сентября или позже
curl -XGET "$ES_URL/blog/post/_search?pretty" -d'
{
  "filter": {
    "range": {
      "published_at": { "gte": "2014-09-01" }
    }
  }
}'

Filtre pa tags

Nou itilize demann tèm pou chèche idantifikasyon dokiman ki gen yon mo bay:

# найдем все документы, в поле tags которых есть элемент 'котята'
curl -XGET "$ES_URL/blog/post/_search?pretty" -d'
{
  "_source": [
    "title",
    "tags"
  ],
  "filter": {
    "term": {
      "tags": "котята"
    }
  }
}'
{
  "took" : 9,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "failed" : 0
  },
  "hits" : {
    "total" : 2,
    "max_score" : 1.0,
    "hits" : [ {
      "_index" : "blog",
      "_type" : "post",
      "_id" : "1",
      "_score" : 1.0,
      "_source" : {
        "title" : "Веселые котята",
        "tags" : [ "котята", "смешная история" ]
      }
    }, {
      "_index" : "blog",
      "_type" : "post",
      "_id" : "3",
      "_score" : 1.0,
      "_source" : {
        "title" : "Как у меня появился котенок",
        "tags" : [ "котята" ]
      }
    } ]
  }
}

Rechèch tèks konplè

Twa nan dokiman nou yo genyen sa ki annapre yo nan domèn kontni an:

  • <p>Смешная история про котят<p>
  • <p>Смешная история про щенков<p>
  • <p>Душераздирающая история про бедного котенка с улицы<p>

Nou itilize matche rechèch pou chèche idantifikasyon dokiman ki gen yon mo bay:

# source: false означает, что не нужно извлекать _source найденных документов
curl -XGET "$ES_URL/blog/post/_search?pretty" -d'
{
  "_source": false,
  "query": {
    "match": {
      "content": "история"
    }
  }
}'
{
  "took" : 13,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "failed" : 0
  },
  "hits" : {
    "total" : 3,
    "max_score" : 0.11506981,
    "hits" : [ {
      "_index" : "blog",
      "_type" : "post",
      "_id" : "2",
      "_score" : 0.11506981
    }, {
      "_index" : "blog",
      "_type" : "post",
      "_id" : "1",
      "_score" : 0.11506981
    }, {
      "_index" : "blog",
      "_type" : "post",
      "_id" : "3",
      "_score" : 0.095891505
    } ]
  }
}

Sepandan, si nou chache "istwa" nan jaden contenu, nou p'ap jwenn anyen, paske Endèks la gen sèlman mo orijinal yo, pa tij yo. Yo nan lòd yo fè yon rechèch-wo kalite, ou bezwen konfigirasyon analizè a.

Jaden _score montre enpòtans. Si demann lan egzekite nan yon kontèks filtre, Lè sa a, valè _score a ap toujou egal a 1, ki vle di yon match konplè ak filtè a.

Analisè yo

Analisè yo yo bezwen konvèti tèks sous la nan yon seri siy.
Analizè yo konpoze de youn Tokenizer ak plizyè opsyonèl TokenFilters. Tokenizer ka anvan pa plizyè CharFilters. Tokenizers kraze fisèl sous la nan siy, tankou espas ak karaktè ponktiyasyon. TokenFilter ka chanje siy, efase oswa ajoute nouvo, pou egzanp, kite sèlman tij mo a, retire prepozisyon, ajoute sinonim. CharFilter - chanje tout fisèl sous la, pou egzanp, koupe tags html.

ES gen plizyè analizeur estanda. Pou egzanp, yon analizeur Ris.

Ann pwofite api epi ann wè ki jan analizè estanda ak Ris yo transfòme fisèl "Istwa komik sou ti chat":

# используем анализатор standard       
# обязательно нужно перекодировать не ASCII символы
curl -XGET "$ES_URL/_analyze?pretty&analyzer=standard&text=%D0%92%D0%B5%D1%81%D0%B5%D0%BB%D1%8B%D0%B5%20%D0%B8%D1%81%D1%82%D0%BE%D1%80%D0%B8%D0%B8%20%D0%BF%D1%80%D0%BE%20%D0%BA%D0%BE%D1%82%D1%8F%D1%82"
{
  "tokens" : [ {
    "token" : "веселые",
    "start_offset" : 0,
    "end_offset" : 7,
    "type" : "<ALPHANUM>",
    "position" : 0
  }, {
    "token" : "истории",
    "start_offset" : 8,
    "end_offset" : 15,
    "type" : "<ALPHANUM>",
    "position" : 1
  }, {
    "token" : "про",
    "start_offset" : 16,
    "end_offset" : 19,
    "type" : "<ALPHANUM>",
    "position" : 2
  }, {
    "token" : "котят",
    "start_offset" : 20,
    "end_offset" : 25,
    "type" : "<ALPHANUM>",
    "position" : 3
  } ]
}
# используем анализатор russian
curl -XGET "$ES_URL/_analyze?pretty&analyzer=russian&text=%D0%92%D0%B5%D1%81%D0%B5%D0%BB%D1%8B%D0%B5%20%D0%B8%D1%81%D1%82%D0%BE%D1%80%D0%B8%D0%B8%20%D0%BF%D1%80%D0%BE%20%D0%BA%D0%BE%D1%82%D1%8F%D1%82"
{
  "tokens" : [ {
    "token" : "весел",
    "start_offset" : 0,
    "end_offset" : 7,
    "type" : "<ALPHANUM>",
    "position" : 0
  }, {
    "token" : "истор",
    "start_offset" : 8,
    "end_offset" : 15,
    "type" : "<ALPHANUM>",
    "position" : 1
  }, {
    "token" : "кот",
    "start_offset" : 20,
    "end_offset" : 25,
    "type" : "<ALPHANUM>",
    "position" : 3
  } ]
}

Analizè estanda a fann fisèl la an espas epi konvèti tout bagay an minuskil, analizè Ris la retire mo ki pa enpòtan, konvèti li an minskil epi kite tij mo yo.

Ann wè ki Tokenizer, TokenFilters, CharFilters analizeur Ris la itilize:

{
  "filter": {
    "russian_stop": {
      "type":       "stop",
      "stopwords":  "_russian_"
    },
    "russian_keywords": {
      "type":       "keyword_marker",
      "keywords":   []
    },
    "russian_stemmer": {
      "type":       "stemmer",
      "language":   "russian"
    }
  },
  "analyzer": {
    "russian": {
      "tokenizer":  "standard",
      /* TokenFilters */
      "filter": [
        "lowercase",
        "russian_stop",
        "russian_keywords",
        "russian_stemmer"
      ]
      /* CharFilters отсутствуют */
    }
  }
}

Ann dekri analizè nou an ki baze sou Ris, ki pral koupe tags html. Ann rele li default, paske yon analizeur ki gen non sa a pral itilize pa default.

{
  "filter": {
    "ru_stop": {
      "type":       "stop",
      "stopwords":  "_russian_"
    },
    "ru_stemmer": {
      "type":       "stemmer",
      "language":   "russian"
    }
  },
  "analyzer": {
    "default": {
      /* добавляем удаление html тегов */
      "char_filter": ["html_strip"],
      "tokenizer":  "standard",
      "filter": [
        "lowercase",
        "ru_stop",
        "ru_stemmer"
      ]
    }
  }
}

Premyèman, tout etikèt HTML yo pral retire nan fisèl sous la, Lè sa a, estanda tokenizer la pral divize l 'nan marqueur, marqueur ki kapab lakòz yo ap deplase nan miniskil, mo ensiyifyan yo pral retire, ak marqueur ki rete yo ap rete tij la nan mo a.

Kreye yon endèks

Pi wo a nou dekri analizè default la. Li pral aplike nan tout jaden fisèl. Pòs nou an gen yon seri de tags, kidonk tag yo pral trete pa analizè a tou. Paske Nou ap chèche pòs pa matche egzak nan yon tag, Lè sa a, nou bezwen enfim analiz pou jaden an tags.

Ann kreye yon endèks blog2 ak yon analizeur ak kat, nan ki analiz la nan jaden tags la enfim:

curl -XPOST "$ES_URL/blog2" -d'
{
  "settings": {
    "analysis": {
      "filter": {
        "ru_stop": {
          "type": "stop",
          "stopwords": "_russian_"
        },
        "ru_stemmer": {
          "type": "stemmer",
          "language": "russian"
        }
      },
      "analyzer": {
        "default": {
          "char_filter": [
            "html_strip"
          ],
          "tokenizer": "standard",
          "filter": [
            "lowercase",
            "ru_stop",
            "ru_stemmer"
          ]
        }
      }
    }
  },
  "mappings": {
    "post": {
      "properties": {
        "content": {
          "type": "string"
        },
        "published_at": {
          "type": "date"
        },
        "tags": {
          "type": "string",
          "index": "not_analyzed"
        },
        "title": {
          "type": "string"
        }
      }
    }
  }
}'

Ann ajoute menm 3 pòs yo nan endèks sa a (blog2). Mwen pral omisyon pwosesis sa a paske... li sanble ak ajoute dokiman nan endèks blog la.

Rechèch tèks konplè ak sipò ekspresyon

Ann pran yon gade nan yon lòt kalite demann:

# найдем документы, в которых встречается слово 'истории'
# query -> simple_query_string -> query содержит поисковый запрос
# поле title имеет приоритет 3
# поле tags имеет приоритет 2
# поле content имеет приоритет 1
# приоритет используется при ранжировании результатов
curl -XPOST "$ES_URL/blog2/post/_search?pretty" -d'
{
  "query": {
    "simple_query_string": {
      "query": "истории",
      "fields": [
        "title^3",
        "tags^2",
        "content"
      ]
    }
  }
}'

Paske Nou ap itilize yon analizeur ak tij Ris, Lè sa a, demann sa a pral retounen tout dokiman, byenke yo sèlman gen mo 'istwa'.

Demann lan ka genyen karaktè espesyal, pa egzanp:

""fried eggs" +(eggplant | potato) -frittata"

Sentaks demann:

+ signifies AND operation
| signifies OR operation
- negates a single token
" wraps a number of tokens to signify a phrase for searching
* at the end of a term signifies a prefix query
( and ) signify precedence
~N after a word signifies edit distance (fuzziness)
~N after a phrase signifies slop amount
# найдем документы без слова 'щенки'
curl -XPOST "$ES_URL/blog2/post/_search?pretty" -d'
{
  "query": {
    "simple_query_string": {
      "query": "-щенки",
      "fields": [
        "title^3",
        "tags^2",
        "content"
      ]
    }
  }
}'

# получим 2 поста про котиков

Referans

PS

Si w enterese nan atik-leson sa yo, si w gen lide pou nouvo atik oswa si w gen pwopozisyon pou koperasyon, m ap kontan resevwa yon mesaj pèsonèl oswa pa imèl nan m.kuzmin+habr@darkleaf.ru.

Sous: www.habr.com