Elasticsearch er leitarvél með json rest api, sem notar Lucene og er skrifuð í Java. Lýsing á öllum kostum þessarar vélar er að finna á
Svipaðar vélar eru notaðar fyrir flókna leit í skjalagagnagrunni. Til dæmis, leit með hliðsjón af formgerð tungumálsins eða leit eftir landhnitum.
Í þessari grein mun ég tala um grunnatriði ES með því að nota dæmið um að skrá bloggfærslur. Ég skal sýna þér hvernig á að sía, flokka og leita í skjölum.
Til þess að vera ekki háður stýrikerfinu mun ég senda allar beiðnir til ES með CURL. Það er líka viðbót fyrir google króm sem heitir
Textinn inniheldur tengla á skjöl og aðrar heimildir. Í lokin eru tenglar fyrir skjótan aðgang að skjölunum. Skilgreiningar á ókunnugum hugtökum er að finna í
Uppsetning
Til að gera þetta þurfum við fyrst Java. Hönnuðir
ES dreifing er aðgengileg á bin/elasticsearch
. Einnig í boði
Eftir uppsetningu og ræsingu skulum við athuga virkni:
# для удобства запомним адрес в переменную
#export ES_URL=$(docker-machine ip dev):9200
export ES_URL=localhost:9200
curl -X GET $ES_URL
Við munum fá eitthvað á þessa leið:
{
"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"
}
Flokkun
Bætum færslu við 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"
}'
svar miðlara:
{
"_index" : "blog",
"_type" : "post",
"_id" : "1",
"_version" : 1,
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"created" : false
}
ES búið til sjálfkrafa
# Получим mapping всех типов индекса blog
curl -XGET "$ES_URL/blog/_mapping?pretty"
Í svari netþjónsins bætti ég við gildum reitanna í verðtryggða skjalinu í athugasemdunum:
{
"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"
}
}
}
}
}
}
Það er athyglisvert að ES gerir ekki greinarmun á einu gildi og fjölda gilda. Til dæmis inniheldur titilreiturinn einfaldlega titil og merkisreiturinn inniheldur fjölda strengja, þó að þeir séu táknaðir á sama hátt í kortlagningu.
Við tölum meira um kortlagningu síðar.
Beiðnir
Að sækja skjal eftir auðkenni þess:
# извлечем документ с 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"
}
}
Nýir lyklar birtust í svarinu: _version
и _source
. Almennt séð eru allir lyklar sem byrja á _
eru flokkaðir sem opinberir.
Lykill _version
sýnir skjalútgáfuna. Það er nauðsynlegt til að bjartsýnn læsibúnaður virki. Til dæmis viljum við breyta skjali sem hefur útgáfu 1. Við sendum inn breytta skjalið og gefum til kynna að þetta sé breyting á skjali með útgáfu 1. Ef einhver annar breytti líka skjali með útgáfu 1 og lagði fram breytingar á undan okkur, þá ES mun ekki samþykkja breytingar okkar, vegna þess það geymir skjalið með útgáfu 2.
Lykill _source
inniheldur skjalið sem við skráðum. ES notar ekki þetta gildi fyrir leitaraðgerðir vegna þess Vísitölur eru notaðar til að leita. Til að spara pláss geymir ES þjappað frumskjal. Ef við þurfum aðeins auðkennið, en ekki allt upprunaskjalið, þá getum við slökkt á upprunageymslu.
Ef við þurfum ekki frekari upplýsingar getum við aðeins fengið innihald _source:
curl -XGET "$ES_URL/blog/post/1/_source?pretty"
{
"title" : "Веселые котята",
"content" : "<p>Смешная история про котят<p>",
"tags" : [ "котята", "смешная история" ],
"published_at" : "2014-09-12T20:44:42+00:00"
}
Þú getur líka valið aðeins ákveðna reiti:
# извлечем только поле title
curl -XGET "$ES_URL/blog/post/1?_source=title&pretty"
{
"_index" : "blog",
"_type" : "post",
"_id" : "1",
"_version" : 1,
"found" : true,
"_source" : {
"title" : "Веселые котята"
}
}
Við skulum skrá nokkrar færslur í viðbót og keyra flóknari fyrirspurnir.
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"
}'
Raða
# найдем последний пост по дате публикации и извлечем поля 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 ]
} ]
}
}
Við völdum síðustu færsluna. size
takmarkar fjölda skjala sem á að gefa út. total
sýnir heildarfjölda skjala sem passa við beiðnina. sort
í úttakinu inniheldur fjölda heiltalna sem flokkun er framkvæmd eftir. Þeir. dagsetningunni var breytt í heila tölu. Frekari upplýsingar um flokkun er að finna í
Síur og fyrirspurnir
ES þar sem útgáfa 2 gerir ekki greinarmun á síum og fyrirspurnum í staðinn
Fyrirspurnarsamhengi er frábrugðið síusamhengi að því leyti að fyrirspurnin býr til _score og er ekki í skyndiminni. Ég mun sýna þér hvað _score er seinna.
Sía eftir dagsetningu
Við notum beiðnina
# получим посты, опубликованные 1ого сентября или позже
curl -XGET "$ES_URL/blog/post/_search?pretty" -d'
{
"filter": {
"range": {
"published_at": { "gte": "2014-09-01" }
}
}
}'
Sía eftir merkjum
Við notum
# найдем все документы, в поле 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" : [ "котята" ]
}
} ]
}
}
Full textaleit
Þrjú skjöl okkar innihalda eftirfarandi í efnisreitnum:
<p>Смешная история про котят<p>
<p>Смешная история про щенков<p>
<p>Душераздирающая история про бедного котенка с улицы<p>
Við notum
# 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
} ]
}
}
Hins vegar, ef við leitum að „sögum“ í innihaldsreitnum, finnum við ekki neitt, vegna þess að Skráin inniheldur aðeins upprunalegu orðin, ekki stofna þeirra. Til að gera hágæða leit þarftu að stilla greiningartækið.
Field _score
sýnir
Greiningartæki
Greiningartæki samanstanda af einum
ES hefur nokkra
Nýtum okkur
# используем анализатор 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
} ]
}
Staðlaða greiningartækið klofnaði strenginn í bil og breytti öllu í lágstafi, rússneski greiningartækið fjarlægði ómikilvæg orð, breytti því í lágstafi og skildi eftir stofn orðanna.
Við skulum sjá hvaða Tokenizer, TokenFilters, CharFilters rússneski greiningartækið notar:
{
"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 отсутствуют */
}
}
}
Við skulum lýsa greiningartækinu okkar byggt á rússnesku, sem mun klippa út html merki. Við skulum kalla það sjálfgefið, vegna þess að greiningartæki með þessu nafni verður sjálfgefið notað.
{
"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"
]
}
}
}
Í fyrsta lagi verða öll HTML merki fjarlægð úr upprunastrengnum, síðan mun tákngerarstaðalinn skipta honum í tákn, táknin sem myndast munu færast yfir í lágstafi, óveruleg orð verða fjarlægð og táknin sem eftir eru verða áfram stofn orðsins.
Að búa til vísitölu
Hér að ofan lýstum við sjálfgefna greiningartækinu. Það mun gilda um alla strengareiti. Færslan okkar inniheldur fjölda merkja, þannig að merkin verða einnig unnin af greiningartækinu. Vegna þess að Við erum að leita að færslum eftir nákvæmri samsvörun við merki, þá þurfum við að slökkva á greiningu fyrir merki reitinn.
Við skulum búa til vísitölublogg2 með greiningartæki og kortlagningu, þar sem greining á merkjareitnum er óvirk:
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"
}
}
}
}
}'
Við skulum bæta sömu 3 færslunum við þessa skrá (blogg2). Ég mun sleppa þessu ferli vegna þess að... það er svipað og að bæta skjölum við bloggskrána.
Full textaleit með tjáningarstuðningi
Við skulum skoða aðra tegund af beiðni:
# найдем документы, в которых встречается слово 'истории'
# 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"
]
}
}
}'
Vegna þess að Við erum að nota greiningartæki með rússneskri stemmningu, þá mun þessi beiðni skila öllum skjölum, þó þau innihaldi aðeins orðið 'saga'.
Beiðnin getur innihaldið sérstafi, til dæmis:
""fried eggs" +(eggplant | potato) -frittata"
Biðja um setningafræði:
+ 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 поста про котиков
tilvísanir
PS
Ef þú hefur áhuga á sambærilegum greinarkennslu, hefur hugmyndir að nýjum greinum eða ert með tillögur að samstarfi, þá mun ég glaður fá skilaboð í persónulegum skilaboðum eða með tölvupósti [netvarið].
Heimild: www.habr.com