የላስቲክ ፍለጋ መሰረታዊ ነገሮች

Elasticsearch ሉሴን በመጠቀም እና በጃቫ የተጻፈ json rest api ያለው የፍለጋ ሞተር ነው። የዚህ ሞተር ሁሉም ጥቅሞች መግለጫ በ ላይ ይገኛል። ኦፊሴላዊ ድር ጣቢያ. በሚከተለው ውስጥ Elasticsearchን እንደ ኢኤስ እንጠቅሳለን።

በሰነድ ዳታቤዝ ውስጥ ለተወሳሰቡ ፍለጋዎች ተመሳሳይ ሞተሮች ጥቅም ላይ ይውላሉ። ለምሳሌ የቋንቋውን ዘይቤ ግምት ውስጥ በማስገባት ፍለጋ ወይም በጂኦ መጋጠሚያዎች መፈለግ።

በዚህ ጽሑፍ ውስጥ የብሎግ ልጥፎችን በማውጣት ምሳሌ በመጠቀም ስለ ኢኤስ መሰረታዊ ነገሮች እናገራለሁ. ሰነዶችን እንዴት ማጣራት፣ መደርደር እና መፈለግ እንደሚችሉ አሳይሻለሁ።

በስርዓተ ክወናው ላይ ላለመመካት፣ CURL ን በመጠቀም ሁሉንም ጥያቄዎችን ለ ES አቀርባለሁ። ለ google chrome የሚባል ተሰኪም አለ። ስሜት.

ጽሑፉ ወደ ሰነዶች እና ሌሎች ምንጮች አገናኞችን ይዟል. በመጨረሻ ወደ ሰነዶቹ በፍጥነት ለመድረስ አገናኞች አሉ። የማይታወቁ ቃላት ፍቺዎች በ ውስጥ ይገኛሉ መዝገበ ቃላት.

ኢኤስን በመጫን ላይ

ይህንን ለማድረግ በመጀመሪያ ጃቫ ያስፈልገናል. ገንቢዎች ይመክራሉ ከJava 8 update 20 ወይም Java 7 update 55 የበለጠ አዳዲስ የጃቫ ስሪቶችን ጫን።

የ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
}

ኢኤስ በራስ-ሰር ተፈጥሯል። መረጃ ጠቋሚ ብሎግ እና ይተይቡ ልጥፍ. ሁኔታዊ ተመሳሳይነት መሳል እንችላለን፡ ኢንዴክስ የውሂብ ጎታ ነው፣ ​​እና አይነት በዚህ ዳታቤዝ ውስጥ ሰንጠረዥ ነው። እያንዳንዱ አይነት የራሱ እቅድ አለው - የካርታ ስራልክ እንደ የግንኙነት ጠረጴዛ. ሰነዱ ሲጠቆም ካርታ ስራ በራስ ሰር ይፈጠራል፡-

# Получим 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 ጋር መሆኑን እንጠቁማለን። ES የእኛን ለውጦች አይቀበልም፣ ምክንያቱም ሰነዱን በስሪት 1 ያከማቻል።

ቁልፍ _source ኢንዴክስ ያደረግነው ሰነድ ይዟል። ES ይህን ዋጋ ለፍለጋ ስራዎች አይጠቀምም ምክንያቱም ኢንዴክሶች ለመፈለግ ጥቅም ላይ ይውላሉ. ቦታን ለመቆጠብ ES የታመቀ የምንጭ ሰነድ ያከማቻል። መታወቂያውን ብቻ የምንፈልግ ከሆነ እና ሙሉውን የምንጭ ሰነዱ ካልሆነ የምንጭ ማከማቻን ማሰናከል እንችላለን።

ተጨማሪ መረጃ ካልፈለግን የ_ምንጭ ይዘቶችን ብቻ ማግኘት እንችላለን፡-

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 በውጤቱ ውስጥ መደርደር የሚከናወነው የኢንቲጀር ድርድር ይዟል። እነዚያ። ቀኑ ወደ ኢንቲጀር ተቀይሯል። ስለ መደርደር ተጨማሪ መረጃ በ ውስጥ ይገኛል። ሰነድ.

ማጣሪያዎች እና መጠይቆች

ES ከስሪት 2 ጀምሮ ማጣሪያዎችን እና መጠይቆችን አይለይም፣ ይልቁንም የአውድ ፅንሰ-ሀሳብ ቀርቧል.
የጥያቄ አውድ ከማጣሪያ አውድ የሚለየው መጠይቁ _score የሚያመነጨው እና ያልተሸጎጠ በመሆኑ ነው። በኋላ ላይ _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 ከበርካታ ሊቀድም ይችላል። CharFilters. ማስመሰያዎች የምንጭ ሕብረቁምፊውን እንደ ክፍተቶች እና የስርዓተ-ነጥብ ቁምፊዎች ወደ ቶከኖች ይሰብራሉ። TokenFilter ቶከኖችን መቀየር፣ መሰረዝ ወይም አዳዲሶችን ማከል ይችላል፣ ለምሳሌ የቃሉን ግንድ ብቻ ይተው፣ ቅድመ-አቀማመጦችን ያስወግዳል፣ ተመሳሳይ ቃላትን ይጨምራል። CharFilter - ሙሉውን ምንጭ ሕብረቁምፊ ይለውጣል, ለምሳሌ, html መለያዎችን ይቆርጣል.

ES በርካታ አለው። መደበኛ ተንታኞች. ለምሳሌ, ተንታኝ ራሽያኛ.

እንጠቀምበት ኤፒአይ እና ደረጃውን የጠበቀ እና የሩሲያ ተንታኞች "ስለ ድመቶች አስቂኝ ታሪኮች" የሚለውን ሕብረቁምፊ እንዴት እንደሚቀይሩ እንመልከት.

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

ኤችቲኤምኤል መለያዎችን የሚቆርጠው በሩሲያኛ ላይ በመመርኮዝ የእኛን ተንታኝ እንግለጽ። ነባሪ እንበለው ምክንያቱ ይህ ስም ያለው ተንታኝ በነባሪነት ጥቅም ላይ ይውላል።

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

በመጀመሪያ፣ ሁሉም የኤችቲኤምኤል መለያዎች ከምንጩ ሕብረቁምፊ ይወገዳሉ፣ ከዚያ የማስመሰያ መስፈርቱ ወደ ቶከኖች ይከፋፈላል፣ የተገኙት ቶከኖች ወደ ትናንሽ ሆሄያት ይሸጋገራሉ፣ እዚህ ግባ የማይባሉ ቃላቶች ይወገዳሉ፣ እና የተቀሩት ቶከኖች የቃሉ ግንድ ሆነው ይቆያሉ።

ኢንዴክስ መፍጠር

ከላይ ያለውን ነባሪ ተንታኝ ገለጽን። በሁሉም የሕብረቁምፊ መስኮች ላይ ተፈጻሚ ይሆናል። የእኛ ልጥፍ ብዙ መለያዎችን ይዟል፣ ስለዚህ መለያዎቹ እንዲሁ በተንታኙ ይከናወናሉ። ምክንያቱም ልጥፎችን ከመለያ ጋር በትክክል በማዛመድ እንፈልጋለን፣ ከዚያ ለመለያዎች መስክ ትንታኔን ማሰናከል አለብን።

የመለያዎች መስኩ ትንተና የተሰናከለበት መረጃ ጠቋሚ ብሎግ 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

ተመሳሳይ መጣጥፎችን - ትምህርቶችን ከፈለጉ ፣ ለአዳዲስ መጣጥፎች ሀሳቦች ካሉዎት ፣ ወይም የትብብር ፕሮፖዛል ካለዎት በግል መልእክት ወይም በኢሜል መልእክት ሲደርሰኝ ደስ ይለኛል ። [ኢሜል የተጠበቀ].

ምንጭ: hab.com