Dasar Elasticsearch

Elasticsearch mangrupikeun mesin pencari nganggo json rest api, nganggo Lucene sareng ditulis dina Java. Pedaran sadaya kaunggulan mesin ieu sadia dina ramatloka resmi. Di handap ieu kami bakal ngarujuk kana Elasticsearch salaku ES.

Mesin anu sami dianggo pikeun milarian kompleks dina pangkalan data dokumén. Contona, pilarian nyokot kana akun morfologi basa atawa pilarian ku koordinat geo.

Dina artikel ieu kuring bakal ngobrol ngeunaan dasar ES ngagunakeun conto indexing tulisan blog. Kuring bakal nunjukkeun anjeun kumaha nyaring, nyortir sareng milarian dokumén.

Dina raraga teu gumantung kana sistem operasi, abdi bakal nyieun sagala requests ka ES maké Curl. Aya ogé plugin pikeun google chrome disebut rarasaan.

Téks ngandung tumbu ka dokuméntasi jeung sumber séjén. Dina tungtungna aya tautan pikeun aksés gancang kana dokuméntasi. Watesan istilah anu teu biasa tiasa dipendakan dina glosarium.

Masang ES

Jang ngalampahkeun ieu, urang peryogi Java. Pamekar nyarankeun install versi Java leuwih anyar ti Java 8 update 20 atawa Java 7 update 55.

Distribusi ES sayogi di ramatloka pamekar. Saatos unpacking arsip anjeun kudu ngajalankeun bin/elasticsearch. Ogé sadia bungkusan pikeun apt na yum. aya gambar resmi pikeun docker. Langkung seueur ngeunaan pamasangan.

Saatos instalasi sareng peluncuran, hayu urang pariksa pungsionalitasna:

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

curl -X GET $ES_URL

Kami bakal nampi sapertos kieu:

{
  "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

Hayu urang tambahkeun pos ka 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"
}'

respon server:

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

ES otomatis dijieun indéks blog jeung ngetik pos. Urang tiasa ngagambar analogi kondisional: indéks mangrupikeun pangkalan data, sareng jinis mangrupikeun méja dina pangkalan data ieu. Unggal tipe boga skéma sorangan - pemetaan, kawas tabel relational. Pemetaan dihasilkeun sacara otomatis nalika dokumén diindeks:

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

Dina réspon server, kuring nambihan nilai-nilai widang dokumén anu diindeks dina koméntar:

{
  "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"
          }
        }
      }
    }
  }
}

Perlu dicatet yén ES henteu ngabédakeun antara nilai tunggal sareng sababaraha nilai. Contona, widang judul saukur ngandung judul, sarta widang tag ngandung hiji Asép Sunandar Sunarya ti string, sanajan aranjeunna digambarkeun dina cara nu sarua dina pemetaan.
Urang bakal ngobrol langkung seueur ngeunaan pemetaan engké.

Paménta

Retrieving dokumen ku id na:

# извлечем документ с 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"
  }
}

Konci anyar muncul dina réspon: _version и _source. Sacara umum, sadaya konci dimimitian ku _ digolongkeun kana resmi.

konci _version nembongkeun versi dokumen. Dipikabutuh pikeun mékanisme konci optimis pikeun jalan. Salaku conto, urang hoyong ngarobih dokumén anu ngagaduhan versi 1. Urang ngalebetkeun dokumén anu dirobih sareng nunjukkeun yén ieu mangrupikeun éditan dokumen anu nganggo versi 1. Upami aya anu ogé ngédit dokumén kalayan versi 1 sareng ngalebetkeun parobahan sateuacan urang, maka ES moal nampi parobahan urang, sabab eta nyimpen dokumen jeung versi 2.

konci _source ngandung dokumén anu kami indéks. ES henteu nganggo nilai ieu pikeun operasi milarian sabab Indéks dianggo pikeun milarian. Pikeun ngahemat rohangan, ES nyimpen dokumen sumber anu dikomprés. Upami urang ngan ukur peryogi id, sanés sadayana dokumen sumber, maka urang tiasa nganonaktipkeun panyimpen sumber.

Upami urang henteu peryogi inpormasi tambahan, urang ngan ukur tiasa nampi eusi _source:

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

Anjeun oge bisa milih ukur widang nu tangtu:

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

Hayu urang indéks sababaraha tulisan deui jeung ngajalankeun queries leuwih kompleks.

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"
}'

Urut

# найдем последний пост по дате публикации и извлечем поля 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 ]
    } ]
  }
}

Urang milih pos panungtungan. size ngawatesan jumlah dokumén anu bakal dikaluarkeun. total nunjukkeun jumlah total dokumén anu cocog sareng pamundut. sort dina output ngandung hiji Asép Sunandar Sunarya integer ku nu asihan dipigawé. Jelema. tanggal ieu dirobah jadi integer. Inpo nu langkung lengkep ihwal asihan tiasa dipendakan dina dokuméntasi.

Saringan sareng patarosan

ES saprak versi 2 teu ngabedakeun antara saringan jeung queries, gantina konsép konteks diwanohkeun.
Kontéks query bénten sareng kontéks saringan yén pamundut éta ngahasilkeun _score sareng henteu sindangan. Kuring baris némbongkeun Anjeun naon _score engké.

Nyaring dumasar titimangsa

Kami nganggo pamundut jajaran dina konteks saringan:

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

Nyaring ku tag

Urang make pamundut istilah pikeun milarian id dokumén anu ngandung kecap anu dipasihkeun:

# найдем все документы, в поле 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" : [ "котята" ]
      }
    } ]
  }
}

Pilarian téks lengkep

Tilu dokumén kami ngandung ieu dina widang eusi:

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

Urang make patandingan query pikeun milarian id dokumén anu ngandung kecap anu dipasihkeun:

# 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
    } ]
  }
}

Sanajan kitu, lamun urang neangan "carita" dina widang eusi, urang moal manggihan nanaon, sabab Indéks ngandung ukur kecap aslina, teu batang maranéhanana. Dina raraga nyieun pilarian kualitas luhur, Anjeun kudu ngonpigurasikeun analyzer.

médan _score nunjukkeun relevansi. Upami pamundut dieksekusi dina kontéks saringan, nilai _score bakal salawasna sami sareng 1, anu hartosna pertandingan lengkep sareng saringan.

Analis

Analis diperlukeun pikeun ngarobah téks sumber kana sakumpulan tokens.
Analyzers diwangun ku hiji Tokenizer jeung sababaraha pilihan TokenFilters. Tokenizer bisa dimimitian ku sababaraha CharFilters. Tokenizer megatkeun string sumber jadi tokens, kayaning spasi jeung karakter tanda baca. TokenFilter bisa ngarobah tokens, mupus atawa nambahkeun nu anyar, contona, ninggalkeun ngan batang kecap, miceun prepositions, nambahkeun sinonim. CharFilter - ngarobah sakabéh string sumber, contona, motong kaluar tag html.

ES ngagaduhan sababaraha analyzers baku. Contona, hiji analyzer Rusia.

Hayu urang mangpaatkeun API sareng hayu urang tingali kumaha analisa standar sareng Rusia ngarobih senar "Carita lucu ngeunaan anak ucing":

# используем анализатор 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
  } ]
}

Analis standar ngabagi string ku spasi tur ngarobah sagalana kana hurup leutik, analis Rusia dihapus kecap teu penting, dirobah jadi hurup leutik sarta ninggalkeun batang kecap.

Hayu urang tingali Tokenizer, TokenFilters, CharFilters anu dianggo ku analisa Rusia:

{
  "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 отсутствуют */
    }
  }
}

Hayu urang ngajelaskeun analisa kami dumasar kana Rusia, anu bakal motong tag html. Hayu urang disebut standar, sabab hiji analyzer kalawan ngaran ieu bakal dipaké sacara standar.

{
  "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"
      ]
    }
  }
}

Mimiti, sadaya tag HTML bakal dipiceun tina senar sumber, teras standar tokenizer bakal ngabagi kana token, token anu hasilna bakal ngalih ka hurup leutik, kecap-kecap anu teu penting bakal dipupus, sareng token sésana bakal tetep batang kecap.

Nyiptakeun indéks

Di luhur kami ngajelaskeun analisa standar. Ieu bakal dilarapkeun ka sadaya widang string. Pos kami ngandung sababaraha tag, ku kituna tag ogé bakal diolah ku analisa. Sabab Kami milarian tulisan anu cocog sareng tag, teras urang kedah nganonaktipkeun analisa pikeun widang tag.

Hayu urang ngadamel blog2 indéks kalayan analisa sareng pemetaan, dimana analisa kolom tag dinonaktipkeun:

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"
        }
      }
    }
  }
}'

Hayu urang tambahkeun 3 tulisan anu sami kana indéks ieu (blog2). Kuring bakal ngaleungitkeun prosés ieu kusabab ... éta sami sareng nambihan dokumén kana indéks blog.

Pilarian téks lengkep sareng dukungan éksprési

Hayu urang tingali jinis pamundut anu sanés:

# найдем документы, в которых встречается слово 'истории'
# 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"
      ]
    }
  }
}'

Sabab Kami nganggo analisa nganggo stemming Rusia, teras pamundut ieu bakal ngabalikeun sadaya dokumén, sanaos aranjeunna ngan ukur ngandung kecap 'sajarah'.

Paménta tiasa ngandung karakter khusus, contona:

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

Sintaksis pamundut:

+ 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 поста про котиков

rujukan

PS

Upami anjeun resep kana artikel-palajaran anu sami, gaduh ide pikeun tulisan énggal, atanapi gaduh usulan pikeun gawé babarengan, maka kuring bakal bungah nampi pesen dina pesen pribadi atanapi ku email. [email dijaga].

sumber: www.habr.com