लवचिक शोध मूलभूत

Elasticsearch हे json rest api असलेले एक शोध इंजिन आहे, जे Lucene वापरून आणि Java मध्ये लिहिलेले आहे. या इंजिनच्या सर्व फायद्यांचे वर्णन येथे उपलब्ध आहे अधिकृत वेबसाइट. पुढील गोष्टींमध्ये आम्ही इलास्टिकसर्चचा ES म्हणून संदर्भ घेऊ.

दस्तऐवज डेटाबेसमधील जटिल शोधांसाठी तत्सम इंजिन वापरले जातात. उदाहरणार्थ, भाषेचे आकारविज्ञान लक्षात घेऊन शोधा किंवा भौगोलिक निर्देशांकांद्वारे शोधा.

या लेखात मी अनुक्रमणिका ब्लॉग पोस्टचे उदाहरण वापरून ES च्या मूलभूत गोष्टींबद्दल बोलेन. कागदपत्रे कशी फिल्टर करायची, क्रमवारी लावायची आणि शोधायची हे मी तुम्हाला दाखवतो.

ऑपरेटिंग सिस्टमवर अवलंबून राहू नये म्हणून, मी CURL वापरून ES ला सर्व विनंत्या करेन. गुगल क्रोम नावाचे प्लगइन देखील आहे अर्थ.

मजकूरात दस्तऐवजीकरण आणि इतर स्त्रोतांचे दुवे आहेत. शेवटी दस्तऐवजात द्रुत प्रवेशासाठी दुवे आहेत. अपरिचित संज्ञांच्या व्याख्या आढळू शकतात शब्दकोष.

ES स्थापित करत आहे

हे करण्यासाठी, आपल्याला प्रथम Java आवश्यक आहे. विकसक शिफारस Java 8 अपडेट 20 किंवा Java 7 अपडेट 55 पेक्षा नवीन Java आवृत्त्या स्थापित करा.

ES वितरण येथे उपलब्ध आहे विकसक वेबसाइट. संग्रह अनपॅक केल्यानंतर तुम्हाला चालवावे लागेल bin/elasticsearch. तसेच उपलब्ध आहे apt आणि yum साठी पॅकेजेस. आहे डॉकरसाठी अधिकृत प्रतिमा. स्थापनेबद्दल अधिक.

स्थापना आणि लॉन्च केल्यानंतर, कार्यक्षमता तपासूया:

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

curl -X GET $ES_URL

आम्हाला असे काहीतरी मिळेल:

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

अनुक्रमणिका

चला 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"
}'

सर्व्हर प्रतिसाद:

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

ES आपोआप तयार झाला अनुक्रमणिका ब्लॉग आणि एक प्रकार पोस्ट. आपण सशर्त साधर्म्य काढू शकतो: निर्देशांक हा डेटाबेस आहे आणि या डेटाबेसमधील एक प्रकार एक सारणी आहे. प्रत्येक प्रकाराची स्वतःची योजना असते - मॅपिंग, अगदी रिलेशनल टेबल प्रमाणे. दस्तऐवज अनुक्रमित केल्यावर मॅपिंग स्वयंचलितपणे व्युत्पन्न होते:

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

सर्व्हर प्रतिसादात, मी टिप्पण्यांमध्ये अनुक्रमित दस्तऐवजाच्या फील्डची मूल्ये जोडली:

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

हे लक्षात घेण्यासारखे आहे की ES एकल मूल्य आणि मूल्यांच्या अॅरेमध्ये फरक करत नाही. उदाहरणार्थ, शीर्षक फील्डमध्ये फक्त एक शीर्षक असते आणि टॅग फील्डमध्ये स्ट्रिंगचा अ‍ॅरे असतो, जरी ते मॅपिंगमध्ये त्याच प्रकारे दर्शविले जातात.
आम्ही नंतर मॅपिंगबद्दल अधिक बोलू.

चौकश्या

दस्तऐवज त्याच्या आयडीद्वारे पुनर्प्राप्त करणे:

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

प्रतिसादात नवीन की दिसल्या: _version и _source. सर्वसाधारणपणे, सर्व कळा सुरू होतात _ अधिकृत म्हणून वर्गीकृत आहेत.

की _version दस्तऐवज आवृत्ती दाखवते. आशावादी लॉकिंग यंत्रणा कार्य करण्यासाठी हे आवश्यक आहे. उदाहरणार्थ, आम्हाला आवृत्ती 1 असलेला दस्तऐवज बदलायचा आहे. आम्ही बदललेला दस्तऐवज सबमिट करतो आणि सूचित करतो की हे आवृत्ती 1 सह दस्तऐवजाचे संपादन आहे. जर इतर कोणीही आवृत्ती 1 सह दस्तऐवज संपादित केला असेल आणि आमच्यासमोर बदल सबमिट केले असतील, तर ES आमचे बदल स्वीकारणार नाही, कारण हे दस्तऐवज आवृत्ती 2 सह संग्रहित करते.

की _source आम्ही अनुक्रमित केलेला दस्तऐवज आहे. ES हे मूल्य शोध ऑपरेशनसाठी वापरत नाही कारण अनुक्रमणिका शोधण्यासाठी वापरल्या जातात. जागा वाचवण्यासाठी, ES संकुचित स्त्रोत दस्तऐवज संग्रहित करते. जर आम्हाला फक्त आयडीची आवश्यकता असेल आणि संपूर्ण स्त्रोत दस्तऐवजाची गरज नसेल, तर आम्ही स्त्रोत संचयन अक्षम करू शकतो.

आम्हाला अतिरिक्त माहितीची आवश्यकता नसल्यास, आम्ही फक्त _source ची सामग्री मिळवू शकतो:

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

तुम्ही फक्त काही फील्ड देखील निवडू शकता:

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

चला आणखी काही पोस्ट अनुक्रमित करूया आणि अधिक जटिल प्रश्न चालवू.

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

वर्गीकरण

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

आम्ही शेवटची पोस्ट निवडली. size जारी करायच्या कागदपत्रांची संख्या मर्यादित करते. total विनंतीशी जुळणाऱ्या दस्तऐवजांची एकूण संख्या दाखवते. sort आउटपुटमध्ये पूर्णांकांचा एक अॅरे आहे ज्याद्वारे क्रमवारी लावली जाते. त्या. तारीख पूर्णांकात रूपांतरित झाली. क्रमवारी बद्दल अधिक माहिती मध्ये आढळू शकते दस्तऐवजीकरण.

फिल्टर आणि क्वेरी

आवृत्ती 2 पासून ES, त्याऐवजी फिल्टर आणि क्वेरी यांच्यात फरक करत नाही संदर्भांची संकल्पना मांडली आहे.
क्वेरी संदर्भ फिल्टर संदर्भापेक्षा भिन्न असतो ज्यामध्ये क्वेरी _score व्युत्पन्न करते आणि कॅशे केलेली नसते. मी तुम्हाला नंतर दाखवतो की _स्कोअर काय आहे.

तारखेनुसार फिल्टर करा

आम्ही विनंती वापरतो श्रेणी फिल्टरच्या संदर्भात:

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

टॅगनुसार फिल्टर करा

आम्ही वापरतो टर्म क्वेरी दिलेला शब्द असलेले दस्तऐवज आयडी शोधण्यासाठी:

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

संपूर्ण मजकूर शोध

आमच्या तीन दस्तऐवजांमध्ये सामग्री फील्डमध्ये खालील गोष्टी आहेत:

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

आम्ही वापरतो मॅच क्वेरी दिलेला शब्द असलेले दस्तऐवज आयडी शोधण्यासाठी:

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

तथापि, आम्ही सामग्री फील्डमध्ये "कथा" शोधल्यास, आम्हाला काहीही सापडणार नाही, कारण अनुक्रमणिकेत फक्त मूळ शब्द आहेत, त्यांचे देठ नाहीत. उच्च-गुणवत्तेचा शोध करण्यासाठी, तुम्हाला विश्लेषक कॉन्फिगर करणे आवश्यक आहे.

फील्ड _score शो प्रासंगिकता. विनंती फिल्टर संदर्भात अंमलात आणल्यास, _score मूल्य नेहमी 1 च्या बरोबरीचे असेल, याचा अर्थ फिल्टरशी संपूर्ण जुळणी होईल.

विश्लेषक

विश्लेषक स्त्रोत मजकूर टोकनच्या संचामध्ये रूपांतरित करण्यासाठी आवश्यक आहे.
विश्लेषक एक बनलेले आहेत टोकनायझर आणि अनेक पर्यायी टोकनफिल्टर्स. Tokenizer च्या आधी अनेक असू शकतात चारफिल्टर्स. टोकनायझर्स स्त्रोत स्ट्रिंगला टोकनमध्ये मोडतात, जसे की स्पेस आणि विरामचिन्हे वर्ण. TokenFilter टोकन बदलू शकतो, हटवू शकतो किंवा नवीन जोडू शकतो, उदाहरणार्थ, फक्त शब्दाचा स्टेम सोडा, पूर्वसर्ग काढून टाका, समानार्थी शब्द जोडा. चारफिल्टर - संपूर्ण स्त्रोत स्ट्रिंग बदलते, उदाहरणार्थ, html टॅग कापते.

ES मध्ये अनेक आहेत मानक विश्लेषक. उदाहरणार्थ, विश्लेषक रशियन.

चला लाभ घेऊया API आणि मानक आणि रशियन विश्लेषक "मांजरीचे पिल्लू बद्दल मजेदार कथा" या स्ट्रिंगचे कसे रूपांतर करतात ते पाहूया:

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

मानक विश्लेषकाने स्ट्रिंगला स्पेसद्वारे विभाजित केले आणि सर्वकाही लोअरकेसमध्ये रूपांतरित केले, रशियन विश्लेषकाने बिनमहत्त्वाचे शब्द काढले, ते लोअरकेसमध्ये रूपांतरित केले आणि शब्दांचे स्टेम सोडले.

रशियन विश्लेषक कोणते Tokenizer, TokenFilters, CharFilters वापरतात ते पाहूया:

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

रशियनवर आधारित आमच्या विश्लेषकाचे वर्णन करूया, जे html टॅग कापून टाकेल. चला त्याला डीफॉल्ट म्हणूया, कारण या नावाचा विश्लेषक डीफॉल्टनुसार वापरला जाईल.

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

प्रथम, सर्व HTML टॅग स्त्रोत स्ट्रिंगमधून काढून टाकले जातील, नंतर टोकनायझर मानक ते टोकनमध्ये विभाजित करेल, परिणामी टोकन लोअरकेसमध्ये हलवले जातील, क्षुल्लक शब्द काढून टाकले जातील आणि उर्वरित टोकन शब्दाचे स्टेम राहतील.

निर्देशांक तयार करणे

वर आम्ही डीफॉल्ट विश्लेषक वर्णन केले आहे. हे सर्व स्ट्रिंग फील्डवर लागू होईल. आमच्या पोस्टमध्ये टॅगची अॅरे आहे, त्यामुळे टॅगवर विश्लेषकाद्वारे देखील प्रक्रिया केली जाईल. कारण आम्ही टॅगशी तंतोतंत जुळणारी पोस्ट शोधत आहोत, नंतर आम्हाला टॅग फील्डसाठी विश्लेषण अक्षम करणे आवश्यक आहे.

चला विश्लेषक आणि मॅपिंगसह अनुक्रमणिका ब्लॉग2 तयार करूया, ज्यामध्ये टॅग फील्डचे विश्लेषण अक्षम केले आहे:

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

या अनुक्रमणिका (ब्लॉग3) मध्ये समान 2 पोस्ट जोडूया. मी ही प्रक्रिया वगळेन कारण... हे ब्लॉग इंडेक्समध्ये दस्तऐवज जोडण्यासारखे आहे.

अभिव्यक्ती समर्थनासह संपूर्ण मजकूर शोध

चला दुसर्‍या प्रकारच्या विनंतीवर एक नजर टाकूया:

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

कारण आम्ही रशियन स्टेमिंगसह विश्लेषक वापरत आहोत, नंतर ही विनंती सर्व दस्तऐवज परत करेल, जरी त्यात फक्त 'इतिहास' शब्द असेल.

विनंतीमध्ये विशेष वर्ण असू शकतात, उदाहरणार्थ:

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

विनंती वाक्यरचना:

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

संदर्भ

PS

तुम्हाला समान लेख-धड्यांमध्ये स्वारस्य असल्यास, नवीन लेखांसाठी कल्पना असल्यास, किंवा सहकार्याचे प्रस्ताव असल्यास, मला वैयक्तिक संदेश किंवा ईमेलद्वारे संदेश मिळाल्यास मला आनंद होईल. [ईमेल संरक्षित].

स्त्रोत: www.habr.com