ElasticSearch 學習總結

Assassin就是我發表於2018-09-06

ElasticSearch 學習總結

ElasticSearch 官方網站:www.elastic.co/guide/en/el…


安裝

Elastic 需要 Java 8 環境。請參考 這篇文章 來安裝 Java,可以解決環境配置的煩惱!

安裝完 Java 8 後,在終端輸入下面的命令來下載 Elastic 的壓縮包( 版本號請自行修改 )。

$ wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.5.1.zip
$ unzip elasticsearch-5.5.1.zip
$ cd elasticsearch-5.5.1/
複製程式碼

啟動

在一切準備工作(Java 安裝完畢)做好後,進入 Elastic 檔案的根目錄下,輸入下面的命令來啟動 Elastic

$ ./bin/elasticsearch
複製程式碼

啟動完成後,開啟瀏覽器,在位址列輸入 localhost:9200 ,如果出現類似下面的資訊,則說明啟動成功。

{
  "name" : "atntrTf",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "tf9250XhQ6ee4h7YI11anA",
  "version" : {
    "number" : "5.5.1",
    "build_hash" : "19c13d0",
    "build_date" : "2017-07-18T20:44:24.823Z",
    "build_snapshot" : false,
    "lucene_version" : "6.6.0"
  },
  "tagline" : "You Know, for Search"
}
複製程式碼

Ps. 推薦一個 API 請求工具 PostMan ,它可以替代瀏覽器和終端來發起 API 請求,並且可以對返回的資料進行 JSON 格式的轉換,直觀簡潔。

ElasticSearch 學習總結

基本概念

Node(節點) 與 Cluster(叢集)

Elastic 本質上是一個分散式資料庫,允許多臺伺服器協同工作,同時每臺伺服器可以執行多個 Elastic 例項。每個 Elastic 例項稱為節點,一組節點稱為叢集。


Index(索引)

Elastic 中的 Index (索引)相當於關係型資料庫中的 dataBase (資料庫),當然也可以理解為是 table(表)。每個 Index 的名字必須是小寫的。下面的命令可以檢視當前 Elastic 例項下的所有 Index ,包括每個 Index 的文件大小等資訊。

$ curl -X GET 'http://localhost:9200/_cat/indices?v'
複製程式碼

當然,你也可以在上面提到的 PostMan 中輸入上面命令中的路由地址來檢視。


Document(文件)

Index 中的每條資料記錄被稱為 Document(文件)。多條 Document 構成了一個 Index 。所以說 Index 往小了看可以被當做一張表。Document 中的資料結構是以 JSON 格式表示的。

{
  "auth": "Assassin",
  "work": "NodeJS全棧",
  "email": "告訴你才怪@qq.com",
}
複製程式碼

Type(分類)

Index 如果被看做是一個資料庫的話,那 Type 就可以看做是這個資料庫的表。注意,同一 Index 下的 Type 應該具備相似的結構(schema),這一點是跟關係型資料庫的區別。下面的命令是列出當前 Index 下的所有 Type

$ curl 'localhost:9200/_mapping?pretty=true'
複製程式碼

多說一句,ES 與關係型資料庫的各個元素的對比:

Relational DB Database Table Row Colum
ElasticSearch Index Type Document Field

Elastic中的資料型別

這裡只列出常用的資料型別,其餘的遇見再說

  1. String:字串型別,預設會被分詞。其中包括 keywordtext 兩種子型別。

    keyword:儲存資料時,資料不會被分詞建立索引,可以被用來檢索過濾、排序和聚合。如:'牆體鋼結構',keyword 會將它作為一個整體。

    text:儲存資料時,資料會被分詞建立索引,但如果該欄位的資料沒有分詞的必要的話,使用 text 則會浪費儲存空間,text 資料型別不能用來排序和聚合。如:'牆體鋼結構',text 會將它切分為'牆體','鋼結構'。

    分詞器:只針對 text 型別。git 地址為 github.com/medcl/elast… 。其作用就是將文字按照一定的規則進行切分。安裝方法:將下載的分詞外掛解壓到根目錄下的 plugins 中,然後重啟 Elastic 例項。

  2. 數字型別:

    • long:長整型,64 位儲存
    • integer:整型,32 位儲存
    • short:短整型,16 位儲存
    • byte:位元組型,8 位儲存
    • double:雙精度型,64 位儲存
    • float:單精度型,32 位儲存
  3. 其他簡單型別

    • date:時間型別
    • boolean:布林型別
    • binary:位元組型別
  4. 複合型別

    • array:陣列型別
    • object:json 物件型別
    • Array[Object]:物件陣列的巢狀型別

Index的mapping建立

Index 的建立包括了對每張表 Type 的定義。在 JavaScript 和終端中的建立方法如下:

  • JavaScript
import elasticsearch from 'elasticsearch';
const esClient = new elasticsearch.Client({
  host: 'localhost:9200',
  log: 'error',
});
const settings = {
  number_of_shards: 5,
  number_of_replicas: 1,
};
const PromiseList = [
  esClient.indices.create({
    index: 'student',
    body: {
      settings, // index的一些設定
      mappings: {
        // type
        person: {
          // type 的各個欄位
          properties: {
            sno: {
              type: 'long',
            },
            name: {
              type: 'keyword',
            },
            sex: {
              type: 'keyword',
            },
            class: {
              type: 'text',
              analyzer: 'ik_max_word',
              search_analyzer: 'ik_max_word',
              fields: {
                raw: {
                  type: 'keyword',
                  ignore_above: 128,
                },
              },
            },
            register: {
              type: 'date',
            },
          },
        },
        .....
      },
    },
  }),
  .....
];
PromiseList.map(p => p.catch(e => console.log(e.message)));
.....
複製程式碼

上述程式碼中,採用的是通過 Promises 來批量建立資料庫的,如果是隻建立單一的庫可以用 async await

  • 終端
$ curl -X PUT -H 'Content-Type: application/json' 'localhost:9200/student' -d '
{
  mappings: {
    // type
    person: {
    // type 的各個欄位
      properties: {
        sno: {
          type: 'long',
        },
        name: {
          type: 'keyword',
        },
        sex: {
          type: 'keyword',
        },
        class: {
          type: 'text',
          analyzer: 'ik_max_word',
          search_analyzer: 'ik_max_word',
          fields: {
            raw: {
              type: 'keyword',
              ignore_above: 128,
            },
          },
        },
        register: {
          type: 'date',
        },
      },
    },
  },
}'
複製程式碼

上面的程式碼中,建立了一個名為 studentIndex ,其中包括一張 person 的表,表中包含四個欄位:sonnamesexregister

Index的刪除

講完建立,該講刪除了。刪除很簡單:

  • JavaScript
import elasticsearch from 'elasticsearch';
const esClient = new elasticsearch.Client({
  host: 'localhost:9200',
  log: 'error',
});
Promise.all(
  [
    'student',
    .....
  ].map(index =>
    esClient.indices
      .delete({ index })
      .catch(() => console.error(`delete fail: ${index}`))
  )
);
複製程式碼

上述程式碼中,採用的是通過 Promises 來批量刪除資料庫的,如果是隻刪除單一的庫可以用 async await

  • 終端
$ curl -X DELETE 'localhost:9200/student'
複製程式碼

Elastic資料查詢

Elastic 中常用的查詢方法

search, get, count, mget, msearch 等

配置檔案

import elasticSearch from 'elasticsearch';


let _client = null;

export default () => {
  if (!_client) {
    _client = new elasticSearch.Client('localhost:9200');
  }
  return _client;
};
複製程式碼

單條記錄的條件查詢

單挑記錄的條件查詢的查詢結構為一個類似 JSON 的物件

{
  index: database_name,
  type: table_name,
  body: {
    query: {
      bool: {
        filter: {
          term: {
            'field_name': value,
          },
        },
      },
    },
  },
}
複製程式碼

這是一個最簡單的查詢結構

當中的 filter 屬性值為 Object | Array , 其中 Array 為物件陣列。如 [{term: {key: value}}, ...]

當然,查詢不可能這麼簡單,還有其他的可新增的屬性。

term & terms 過濾查詢(匹配查詢)

term 主要用於精確匹配哪些值,比如數字,日期,布林值。一個 term 查詢結構:

{ term: { key: value } }
複製程式碼

與其類似的 terms 主要用來匹配多個條件的過濾查詢。比如

{ terms: 'tag': [ 'react', 'vue', 'angular' ] }
複製程式碼

range 過濾查詢(範圍查詢)

range 過濾允許我們按照指定範圍查詢一批資料

{
  range: {
    age: {
      gte: 18,
      lt: 28,
    }
  }
}
複製程式碼

範圍的關鍵字:

  • gt: 大於

  • gte: 大於等於

  • lt: 小於

  • lte: 小於等於

在查詢結構中的體現:

{
  index: database_name,
  type: table_name,
  body: {
    query: {
      range: {
        age: {
          gte: 18,
          lt: 28,
        }
      }
  },
}
複製程式碼

rangeterm(s) 屬於同級別的屬性,所以可以作為 filter 陣列屬性的值

exists & missing 過濾

exists & missing 用於查詢記錄中是否存在或者沒有某個指定的欄位。

{
  exists: {
    field: 'field_value'
  }
}
複製程式碼

exists & missingterm(s) 屬於同級別的屬性,所以可以作為 filter 陣列屬性的值

bool 過濾

bool 布林邏輯查詢,所包含的關鍵字:

  • must: 相當於 and

  • must_not: 相當於 not

  • should: 相當於 or

用法很簡單,只需替換 filter ,當然,同 filter 一樣的用法。

agg 聚合查詢

對於這一塊,語言描述上會存在一些理解上的差異。畢竟聚合這一塊還是比較龐大的,so 為了更專業還是推薦度娘吧(等我再成長一些了再來做一下總結!!)

ES的aggs

批量條件查詢

批量條件查詢就是對一組不同的查詢條件集依次進行處理的查詢過程,猶如一個批處理。

msearch 批量條件查詢

msearch 就是將一般的條件查詢的結構體放入到一個陣列中,然後將這個陣列再作為查詢結構體。

{
  body: [
    { index: database_1, type: table_1 },
    {
      query: {
        term: { field: value },
      },
    },
    { index: database_2, type: table_2 },
    {
      query: {
        bool: {
          must: {
            term: {
              field: value,
            },
          },
          filter: [
            { term: { field: value } },
            { term: { field: value } },
          ],
        },
      },
    },
}
複製程式碼

從上面的結構體中可以看出,msearch 的查詢結構體是吃從下標0開始,相鄰兩個元素作為一個單一查詢結構體的陣列結構。

mget 批量ID查詢

這個方法適用於已知多個記錄ID的批量查詢

{
  index: database,
  type: table,
  body: {
    ids,
  },
}
複製程式碼

其中 ids 為陣列