الستیک‌سرچ

**الستیک‌سرچ**  موتور جستجو برپایه کتابخانه لوسین است که امکان توزیع‌پذیری چندمستأجری با قابلیت جستجوی تمام متن با موتور پروتکل انتقال ابرمتن و واسط وب بدون JSON دارد.

الستیک‌سرچ به زبان جاوا (زبان برنامه‌نویسی) نوشته‌شده‌است. برپایه طرح تجاری هسته‌باز، بخشی از نرم‌افزار تحت تعدادی از مجوزهای آزاد قرار دارد که اکثراً مجوز آپاچی هستند و بخش‌های دیگر تحت مالکیت هستند و کد شامل شرایط نرم‌افزار کد موجود، مجوز الستیک‌سرچ هستند.

کلاینت‌های رسمی در زبان‌های جاوا، دات‌نت (سی شارپ)، پی‌اچ‌پی، پایتون، گرووی، روبی و بسیاری از زبان‌های دیگر موجودند.

بر اساس رتبه‌بندی‌های رسمی، الستیک‌سرچ پرطرفدارترین موتور جستجوی تجاری است که بعد از آن Apache Solr برپایه کتابخانه لوسین قرار دارد.

## تاریخچه
همه‌چیز با یک برنامهٔ دستور آشپزی شروع شد. در سال ۲۰۰۰، شای بانون (Shay Banon) که در لندن زندگی می‌کرد به دنبال کار بود و همسرش به یک مدرسه آشپزی می‌رفت. شای در وقت آزاد خود شروع به نوشتن یک موتور جستجو برای دستورهای آشپزی همسرش کرد و همین باعث شد قصهٔ او رقم بخورد. اولین خروجی او کامپس (compass) نام داشت و نسخهٔ بعدی او الاستیک سرچ نام گرفت. او پروژهٔ خود را متن باز کرد و بسیار مورد استقبال کاربران قرار گرفت. پس از شکل گرفتن جامعه، شای به همراه استیون شوورمن (Steven Schuurman)، آوری بونس (Uri Boness) و سیمون ویلناور (Simon Willnauer) یک شرکت جستجو را تأسیس کردند.

زمانی که شرکت الاستیک سرچ تأسیس شد، دو پروژه متن باز دیگر در دست اجرا بودند.

جردن سیسل (Jordan Sissel) روی پروژهٔ لاگ استش (Logstash) فعالیت می‌کرد. لاگ استش یک ابزار برای ارسال لاگ‌ها به انبار داده کاربر بود که یکی از این انبارهای داده الاستیک سرچ بود. او همچنین مشغول توسعه یک رابط کاربری برای مشاهدهٔ لاگ‌های ارسالی بود اما چندان تعریفی نداشت.

در همان زمان رشید خان (Rashid Khan) مشغول توسعه یک پروژه رابط کاربری به نام کیبانا (Kibana) بود.

شای، جردن و رشید مدتی بود که یکدیگر را می‌شناختند و نهایتاً تصمیم گرفتند تا به هم ملحق شوند. نتیجهٔ این الحاق شرکت ELK Stack بود که به معنای Elasticsearch, Logstash, and Kibana Stack بود.

مدتی بعد آن‌ها دو محصول مارول (Marvel) برای مانیتورینگ و شیلد (Shield) برای امنیت را ارائه کردند.

## ویژگی‌ها
الستیک‌سرچ می‌تواند برای جستجوی انواع اسناد مورد استفاده قرار گیرد. این الگوریتم امکان جستجوی مقیاس‌پذیر را فراهم می‌کند. الستیک‌سرچ توزیع شده‌است، به این معنی که ایندکس‌ها را می‌تواند به قطعات تقسیم کرند و هر یک می‌تواند صفر یا بیشتر کپی داشته باشد. هر گره میزبان یک یا چند تکه دیگر است و به عنوان یک هماهنگ‌کننده برای محول کردن عملیات به قطعه(ها) درست عمل می‌کند. ترازیابی و مسیریابی به‌طور خودکار انجام می‌شوند. داده‌های مرتبط اغلب در همان ایندکس ذخیره می‌شوند. زمانی که یک ایندکس ایجاد شد، تعداد قطعات ابتدایی را نمی‌توان تغییر داد.

ورودی‌های الستیک‌سرچ می‌تواند از منابع و انواع داده‌ای بسیار متنوعی باشد. به عنوان مثال ممکن است ورودی آن برخی از متغیرهای مربوط به وضعیت یک سامانه مانند فرکانس پردازنده، وضعیت حافظهٔ اصلی، دیسک و مواردی از این دست باشد، یا این که ورودی آن مجموعه‌ای از داده‌های متنی یا مجوعه‌ای از لاگ‌های یک سامانه باشد.

به دلیل گسترهٔ وسیع داده‌هایی که استیک‌سرچ پشتیبانی می‌کند و همچنین توانایی ایندکس کردن انواع مختلف داده، از آن در موارد زیر استفاده می‌شود:
* جستجو در برنامه‌ها
* جستجو در وبسایت‌ها
* جمع‌آوری و تحلیل لاگ
* نظارت بر وضعیت و متغیرهای زیرساخت‌ها
* نظارت بر عملکرد کانتینرها
* نظارت بر سطح عملکرد برنامه‌ها
* تحلیل داده‌های جغرافیای
* تحلیل داده‌های مرتبط با امنیت
* تحلیل داده‌های مرتبط با کسب‌وکارها
* مصورسازی داده‌ها

الستیک‌سرچ در کنار مجموعه داده و موتور تجزیه سیاهه بنام Logstash، تجزیه و تحلیل و پلتفرم بصری به نام Kibana و Beats، مجموعه‌ای از حاملان اطلاعات سبک توسعه داده می‌شود. این چهار محصول به عنوان یک راه‌حل یکپارچه طراحی شده‌اند که آن را «الستیک استک» می‌نامند.

الستیک‌سرچ از کتابخانهٔ اوسین استفاده می‌کند و سعی می‌کند تمام ویژگی‌های خود را از طریق API در دسترس قرار دهد.

ویژگی «گیت» یا «دروازه» تداوم طولانی‌مدت ایندکس را بررسی می‌کند؛ به عنوان مثال، یک ایندکس را می‌توان از گیت رویداد خاموش شدن سرور تهیه کرد.

در ۲۰ می ۲۰۱۹ ویژگی‌های امنیتی اصلی الستیک استک در دسترس قرار گرفت، که شامل ارتباطات رمز شده، ایجاد و مدیریت کاربران، و کنترل دسترسی کاربر به APIها و ایندکس‌ها است. کد منبع مورد نظر تحت «مجوز الستیک»، یک مجوز کد-موجود است.

## آنالیز متن
آنالیز متن به الاستیک سرچ این قابلیت را می‌دهد که علاوه بر جستجوی دقیق عبارت، عبارات مرتبط با عبارت وارد شده که احتمالاً مورد نظر کاربرد بوده را نیز پیدا کند.
به عنوان مثال با جستجوی عبارت Quick fox jumps می‌تواند عبارت A quick brown fox jumps over the lazy dog را شناسایی کرد.
به‌طور کلی در طی دو مرحله تبدیل کردن به توکن (Tokenization) و نرمال‌سازی (Normalization) این فرایند صورت می‌گیرد.
در حالت عادی زمانی که یک عبارت مرکب مانند fox jumps جستجو می‌شود، جمله‌ای که متشکل از اجزای این عبارت باشد شناسایی نمی‌شود؛ برای حل این مشکل، عبارات به بخش‌های کوچکتری به نام توکن (token) تجزیه می‌شوند و توکن‌ها جستجو می‌شوند.

علاوه بر شکستن عبارات به توکن‌ها، یک مرحلهٔ دیگر به نام نرمال‌سازی انجام می‌گیرد. برای مثلاً عبارت jump با leap یا حتی با jumps منطبق نمی‌شود، بنابراین برای حل این مشکل عبارات نرمال می‌شوند. نرمال‌سازی شامل مراحل متفاوتی است مانند:
* تبدیل تمام عبارات به حروف کوچک
* تغییر توکن‌ها به توکن ریشه (مانند تغییر کلمات جمع به مفرد)
* جایگزین توکن‌های هم‌معنی به توکن رایج
به‌طور کلی آنالیزگرها (analyzer) عملیات آنالیز متن را انجام می‌دهند. الاستیک سرچ از یک آنالیزگر استاندارد استفاده می‌کند که پاسخ اغلب نیازهای روزمره را می‌دهد اما می‌تواند از یک آنالیزگر دلخواه استفاده کند تا پاسخ نیازهای خاص‌تر و متفاوت‌تری را بدهد.

## کلیدواژه‌های الستیک‌سرچ
در الستیک‌سرچ کلیدواژه‌هایی وجود دارد که متناظری تقریبی با برخی کلیدواژه‌های پایگاه‌داده‌های رابطه‌ای است. در زیر به چند مورد از این مقایسه‌ها پرداخته شده.

## نصب الستیک‌سرچ و کیبانا
برای نصب الستیک‌سرچ اینجا را کلیک کنید. برای نصب کیبانا نیز اینجا را کلیک کنید.

نصب این دو راه‌های مختلفی دارد ولی راهی که اینجا بررسی می‌شود دانلود فایل‌های نصبی با پسوند `deb.` در سیستم‌عامل لینوکس است. پس از دانلود، روی فایل کلیک کرده و نصب کنید یا از کامند زیر استفاده کنید:
```text
sudo dpkg -i [.deb File's name]
```
پس از نصب هر دو عبارات زیر را در ترمینال وارد کنید:
```text
sudo systemctl start elasticsearch
```
برای بررسی اینکه الستیک‌سرچ فعال شده‌است یا نه دو راه دارید:

۱. کامند زیر را در ترمینال وارد کنید و متن پاسخ ترمینال را بررسی کنید که وضعیت الستیک را active نوشته‌است یا failed:
```text
sudo systemctl status elasticsearch
```
۲. الستیک به صورت پیش‌فرض روی پورت ۹۲۰۰ بالا می‌آید. پس در مرورگرتان آدرس زیر را وارد کنید. اگر پاسخی به صورت json و شبیه به پاسخ زیر دریافت کردید یعنی الاستیک فعال است.
```text
localhost:9200
```

```json
{
  "name" : "your Laptop/PC name",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "vQJnbkRIKF2cMd4GmhwvHw",
  "version" : {
    "number" : "7.10.2",
    "build_flavor" : "default",
    "build_type" : "deb",
    "build_hash" : "547e1cc232degds253878a59143c1f785afa92b9",
    "build_date" : "2021-01-13T00:42:12.435326Z",
    "build_snapshot" : false,
    "lucene_version" : "8.7.0",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}
```
حال کیبانا را نیز به همین شیوه نصب و فعال کنید. توجه داشته باشید که کیبانا به صورت پیش‌فرض روی پورت ۵۶۰۱ بالا می‌آید. اگر در مرورگرتان آدرس زیر را وارد کنید، محیط کیبانا بالا می‌آید.
```text
localhost:5601
```
بعد از وارد کردن آدرس بالا باید محیطی شبیه به تصویر روبرو را مشاهده کنید.
جایگزین=محیط کیبانا|بندانگشتی|محیط کیبانا

## شروع کار با الستیک‌سرچ با استفاده از کیبانا
پس از ورود به محیط کیبانا، به قسمت Dev Tools رفته و محیط کنسول آن را مشاهده می‌کنیم. کنسول سمت چپ، محلی است برای نوشتن کوئری‌ها و سمت راست، محلی برای نمایش پاسخ سرور الستیک‌سرچ.
بندانگشتی|محیط Dev Tools در کیبانا

برای وارد کردن اولین مستند (Document) به الستیک کد زیر را در کنسول قرار داده و پس از آن دکمه مثلث سبزرنگ را بزنید.
```text
PUT /universities/_doc/1
    {
    "name": "Sharif University of Technology",
    "location": "tehran",
    "rank": 1
    }
```
در کلیدواژه‌های الستیک به universities ایندکس می‌گویند. به doc_ تایپ یا گروه می‌گویند. به شماره بعد آن شناسه یا id گفته می‌شود. برای ایجاد مستند هم می‌توان از PUT استفاده کرد و هم از POST ولی بهتر است برای ایجاد از PUT و برای بروزرسانی از POST استفاده کرد.

برای وارد کردن اطلاعات در الستیک نیازی به ایجاد دیتابیس نیست (برخلاف پایگاه‌داده‌های رابطه‌ای). یعنی با همین عبارت خط اول ایندکس universities ایجاد شده و داده در آن وارد می‌شود.

خروجی الستیک باید این باشد:
```json
{
  "_index" : "universities",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 0,
  "_primary_term" : 1
}
```
در بالا، ورژن به معنای چندمین نسخه مستند، result به معنای این است که این مستند در این ورژن، ایجاد شده یا آپدیت شده یا ….

## ویرایش و بروزرسانی مستندات
برای ویرایش یک مستند دو راه اولیه داریم:

۱. همان کوئری‌ای که برای ایجاد آن استفاده کردیم، بعد از تغییرات دلخواه دوباره وارد کنیم. مثال:
```text
PUT /universities/_doc/1
    {
    "name": "Tehran University",
    "location": "tehran",
    "rank": 1
    }
```
در مثال بالا فیلد name را تغییر داده‌ایم.

بعد از این کوئری، پاسخ زیر را دریافت می‌کنید.
```json
{
  "_index" : "universities",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 2,
  "result" : "updated",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 2,
  "_primary_term" : 1
}
```
می‌بینید که در این پاسخ، نسبت به قبل دو چیز تغییر کرده. اول فیلد ورژن که از یک به دو تبدیل شد و دوم فیلد result که از created به updated تغییر پیدا کرد.

۲. با استفاده از کوئری‌هایی شبیه کوئری زیر:
```text
POST /universities/_update/1
{
"script" : {
        "source": "ctx._source.name = params.sname",
            "lang": "painless",
             "params" : {
                 "sname" : "Sharif University of Technology"
        }
   }
}
```
کد بالا هم باعث ویرایش مستند می‌شود.

فایده روش دوم این است که دیگر نیاز نیست برای بروزرسانی چند فیلد مستند، کل مستند را بنویسیم و در کوئری وارد کنیم. کافی است با مشخص کردن فیلد مورد نظر فقط همان یکی را بروزرسانی کرد. پاسخ این کوئری هم مانند قبل است.
```json
{
  "_index" : "universities",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 3,
  "result" : "updated",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 2,
  "_primary_term" : 1
}
```


## دریافت و حذف مستندات
برای حذف یک مستند با شناسه معین از کوئری زیر استفاده می‌کنیم:
```text
DELETE universities/_doc/1
```
برای دریافت یک مستند با شناسه معین هم از کوئری زیر استفاده می‌کنیم:
```text
GET universities/_doc/1
```
خروجی زیر را مشاهده می‌کنید:
```json
{
  "_index" : "universities",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 3,
  "_seq_no" : 1,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "name" : "Sharif University of Technology",
    "location" : "tehran",
    "rank" : 1
  }
}
```
برای اعمال یکسری محدودیت‌ها در کوئری GET می‌توانیم از کوئری‌های زیر استفاده کنیم؛ مثلاً در کوئری زیر، فقط فیلدهای گفته شده را نشان می‌دهد.
```text
GET universities/_doc/1?_source_includes=name,rank
```
خروجی کوئری بالا به صورت زیر است:
```json
{
  "_index" : "universities",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 3,
  "_seq_no" : 1,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "name" : "Sharif University of Technology",
    "rank" : 1
  }
}
```
یا در کوئری زیر همه فیلدها به جز فیلدهای گفته شده نشان داده می‌شود:
```text
GET universities/_doc/1?_source_excludes=name
```
پاسخ به کوئری بالا به صورت زیر است:
```json
{
  "_index" : "universities",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 3,
  "_seq_no" : 1,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "location" : "tehran",
    "rank" : 1
  }
}
```


## جستجو در مستندات
* روش Multi-Index:

```text
GET _all/_search?q=name:Sharif
```
با این کوئری، روی تمامی ایندکس‌ها جستجو کرده‌ایم و هرجا name با مقداری که Sharif هم در آن است داشتیم آن را در خروجی می‌بینیم.
* Request Body Search:

در این روش با استفاده از زبان DSL می‌توانیم جستارهای خودمان را داخل کوئری زیر تحقق دهیم. مثال:
```text
POST /universities/_doc/_search
{
   "query":{
      "query_string":{
         "query":"Sharif"
      }
   }
}
```
پاسخ کوئری بالا، مستنداتی است که در حداقل یکی از فیلدهای آن، عبارت Sharif به عنوان مقدار آمده باشد. مانند زیر:
```json
{
  "took" : 6,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 0.2876821,
    "hits" : [
      {
        "_index" : "universities",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.2876821,
        "_source" : {
          "name" : "Sharif University of Technology",
          "location" : "tehran",
          "rank" : 1
        }
      }
    ]
  }
}
```

* Match Query:

```text
GET /universities/_search
{
  "query": {
    "match": {
      "name": "Sharif"
    }
  }
}
```
در این روش به دنبال اسنادی هستیم که در بدنه‌شان عبارت Sharif باشد.
* Range Query:

```text
GET /universities/_search
{
  "query": {
    "range": {
      "rank": {
        "gte": 10,
        "lte": 1
      }
    }
  }
}
```
در اینجا خروجی ما مستنداتی با rank یک تا ده است.
* Fuzzy Query:

```text
GET /universities/_search
{
  "query": {
    "match": {
      "body": {
        "query": "tehran",
        "fuzziness": 1
      }
    }
  }
}
```
در این نوع جستجو، مستندات دارای کلماتی که تنها در یک حرف از واژه تحت جستجو تفاوت دارند هم به خروجی ما اضافه می‌شوند؛ مثلاً tehren.
* Aggregation Query: این روش، روش پیچیده‌ایست برای مطالعه آن می‌توانید هم به سایت اصلی الستیک مراجعه کنید.
* Bool Query:

```text
GET /universities/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "title": {
              "query": "tehran",
              "fuzziness": 1
            }
          }
        }
      ],
      "must_not": [
        {
          "match": {
            "rank": 1
          }
        }
      ]
    }
  }
}
```
هدف این روش این است که منطق را در انتخاب پیاده‌کند یعنی بگوید یک فیلد را با مقدار انتخابی جستجو کن به شرط اینکه فیلد دیگر مقدارش مثلاً یک نباشد.
* Multi-Match Query:

```text
GET /universities/_search
{
  "query": {
    "multi_match": {
      "query": "tehran",
      "fields": [
        "name",
        "location"
      ],
      "fuzziness": 1
    }
  }
}
```
این روش زمانی به کار می‌آید که بخواهیم یک کلمهٔ جستجو را در بیش از یک فیلد جستجو کنیم. در مثال بالا کلمه tehran را در اسناد در فیلدهای name و location بررسی می‌کنیم.

## Mapping
مستنداتی که در Indexها هستند قالب مشخصی دارند که به این قالب Mapping می‌گویند. هر فیلد در این مستند، نوع خاصی دارد مثلاً فیلد name از نوع رشته (string) است و فیلد rank از جنس عدد است. اگر عبارت زیر را در کنسول وارد کنید Mapping را مشاهده می‌کنید:
```text
GET /universities/_mapping
```

خروجی:
```json
{
  "universities" : {
    "mappings" : {
      "properties" : {
        "location" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "name" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "rank" : {
          "type" : "long"
        }
      }
    }
  }
}
```


برای مطالعه روش‌ها و موارد بیشتر به سایت اصلی الستیک‌سرچ مراجعه کنید.

## منابع

* 

رده:شرکت‌های فهرست‌شده در بورس اوراق بهادار نیویورک
رده:موتورهای جستجوگر اینترنت
رده:نرم‌افزارهای آزاد نوشته‌شده با جاوا
رده:نرم‌افزارهای مرتبط با پایگاه داده‌ها برای لینوکس
رده:نرم‌افزارهایی که از پروانه عمومی همگانی آفرو استفاده می‌کنند