1. 程式人生 > 實用技巧 >資料庫複習 3 建立表 資料型別

資料庫複習 3 建立表 資料型別

本文是對ElasticSearch元件初步學習的一個知識總結,包括如下章節的內容:

  • 概述
  • 快速上手
  • 邏輯概念
  • 使用者介面
  • 關於ELKB

預備知識:

1、本文對ElasticSerach的介紹會涉及與關係資料庫的對比,為了更好地學習,可提前對關係資料庫的基本概念有所瞭解。
2、ElasticSerach的資料儲存採用JSON的資料格式,為了更好地學習,可提前對JSON的概念有所瞭解。
3、ElasticSerach對外提供的是RESTful Api訪問介面,為了更好地學習,可提前對RESTful的概念有所瞭解。

二、快速上手

ES雖然是一個強大的分散式系統,但其易用性設計的非常好,安裝和使用都很簡單,下面我們來快速體驗下。

(一)安裝

ES需要java環境,最好是java8,需要設定JAVA_HOME環境變數。ES的安裝非常簡單,開箱即用,首先我們可以從官網www.elastic.co下載相應的二進位制版本,對於Windows作業系統,可下載zip檔案,對於linux作業系統,可下載tar檔案。

下載二進位制包後,解壓到任何一個目錄下。如果不做任何配置,則採用預設的配置啟動ES。執行ES安裝目錄下的bin目錄的elasticsearch指令碼(windows下為elasticsearch.bat)則可以以單例項的方式啟動ES。在linux系統中啟動ES有可能會報錯誤,這在下面會詳細介紹。

我們這裡是啟動的ES的單個例項,ES可以以叢集的方式執行(即在多臺機器上啟動多個ES例項)。因為單節點模式和叢集模式從使用角度看並沒有太多的區別,所以本文介紹的都是基於ES在單節點方式執行的。叢集的方式在後續的文章中介紹。

啟動ES後,下面就可以利用ES提供的RESTful API去使用它。我們可以在瀏覽器或任何web工具中輸入 http://localhost:9200 地址,得到如下的資訊(ES系統的基本資訊):

{
  "name" : "H12K5tk",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "2RAwSskjQh6xDxLrDHBTtQ",
  "version" : {
    "number" : "5.6.9",
    "build_hash" : "877a590",
    "build_date" : "2018-04-12T16:25:14.838Z
", "build_snapshot" : false, "lucene_version" : "6.6.1" }, "tagline" : "You Know, for Search" }

返回的是本節點(ES例項的)name,以及ES叢集的一些基本資訊,如叢集名,版本資訊等

(二)啟動錯誤

在Linux系統中啟動ES,可能會報一些錯誤,導致啟動失敗。下面是一些常見的錯誤與解決方案(這也是本文在Centos7系統中啟動ES碰到的問題)。

1、錯誤1:max file descriptors [4096] for elasticsearch process is too low, increase to at least [65536]
錯誤很好理解,就是指es程序可允許開啟的最大檔案數只有4096,太小了,需要提升到65536。因為ES需要開啟很多檔案,最大4096個不夠,需要調整作業系統中的配置。
在Linux的系統中對於程序(Process)會有一些限制(limit),限制有很多種,常見的如對開啟檔案(Open Files)最大數量的限制。在linux中這些限制是分為軟限制(soft limit)和硬限制(hard limit)兩類。它們的區別就是軟限制可以在程式的程序中自行改變(突破限制),而硬限制則不行(除非程式程序有root許可權)。
使用ulimit 命令可以分別檢視軟限制和硬限制,區別是在檢視的引數前加 S 或 H。例如,檢視開啟檔案數限制(引數是n):
#檢視軟限制
ulimit -Sn
#檢視硬限制
ulimit -Hn

改變這個限制的辦法是修改/etc/security/limits.conf檔案,增加配置,如在配置檔案中增加如下資訊:

*     soft    nofile    65536
*     hard    nofile   65536

注意,最前面的 * 代表這個設定對所有程序都有效,如果只對指定程序有效,將*改為具體的程序名。

2、錯誤2:max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

這個錯誤是指Linux程序的vma大小不足,需要提高。這可以修改/etc/sysctl.conf檔案,增加配置vm.max_map_count=262144,如:

vm.max_map_count=262144

修改配置檔案後,執行 命令sysctl -p 讓生效(注意,一定要執行),如:

[hadoop@master bin]$ sudo sysctl -p
[sudo] password for hadoop:
vm.max_map_count = 262144

另外,在作業系統配置檔案被修改後,最好重新登入,確保新的終端能獲取到修改後的資訊。

(三)訪問ES

因為ES對外提供了RESTful的訪問介面,所以我們可以用任意一種web client工具來訪問ES,最簡單的如linux下的curl程式,還可以用如Postman這樣的工具(Postman是一個非常有用的 Http Client 工具,可用來測試 Web 服務),也可以在瀏覽器上安裝外掛,如chrome中的Sense外掛(該外掛可以很方便的操作ES)。

當然我們可以利用第三方http client庫自己編寫程式碼來訪問ES。不過ES自身也提供了JAVA API來操作ES,這個在後面介紹

下面我們使用RESTful API來舉例使用ES。一個完整的REST請求包括如下三部分:
1、操作型別,如GET,PUT,POST,DELETE等
2、URL部分,如http://localhost:9200/blogs/blog/1
3、請求正文內容。對於GET請求,沒有單獨的請求正文內容,請求資訊都包含在URL中。對於PUT,POST等操作,可以帶正文內容,正文內容採用josn的格式,具體下面例子會看到。

ES的REST請求的返回內容的格式絕大部分都是JOSN格式的。也就是說請求和響應的內容都是JSON格式,這樣有較好的一致性。

下面來看具體的例子:

1、插入資料
往ES中插入資料,可以執行如下的操作:

PUT  http://localhost:9200/blogs/blog/1
{
    "title": "es info",
    "content": "about elasticsearch",
    "author": "jack",
    "year":2018
}
這裡執行的是http的PUT操作,url後面跟著的json格式內容是請求的正文,即儲存到ES中的資料。關於該url和json內容的含義我們在後面介紹,這裡只需知道這樣一個簡單的http的PUT請求就把一條json資料儲存到ES中。上述操作我們可以在如Postman這樣的工具中進行。
該請求成功後伺服器返回的資訊如下:
{
  "_index": "blogs",
  "_type": "blog",
  "_id": "1",
  "_version": 1,
  "result": "created",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "created": true
}

上面響應資訊的格式也是josn格式,其中欄位的含義我們後面再介紹。

2、查詢資料

上面往ES中插入了一條資料,下面我們可以利用http的GET操作來獲取剛才插入的資料。http請求如下:

GET  http://localhost:9200/blogs/blog/1

該請求成功後伺服器返回的資訊如下:

{
  "_index": "blogs",
  "_type": "blog",
  "_id": "1",
  "_version": 1,
  "found": true,
  "_source": {
    "title": "es info",
    "content": "about elasticsearch",
    "author": "jack",
    "year": 2018
  }
}

可以看出,返回的josn內容中,相比插入操作,有這幾個欄位的內容發生了變化:

"_version" : 2,
"result" : "updated",
"created" : false

可以看到,記錄的 Id 沒變,但是版本(version)從1變成2操作型別(result)從created變成updatedcreated欄位變成false,因為這次不是新建記錄,而是修改操作。

這時如果我們執行

GET  http://localhost:9200/blogs/blog/1

查詢操作,會看到返回的Document資料是修改後的資料。

ES文件的版本號是有用的,我們在修改資料時,可以傳入一個版本號。這樣當在一個客戶端讀取和更新文件的間隔中,有另外客戶端更新了資料。如果這個客戶端的更新操作傳入了版本號(前面讀取的版本號),這時因為傳入的版本號和當期實際的版本號不一致,就會操作失敗。這樣就防止可能的資料衝突。這也是ES採用樂觀併發控制(OCC)機制的體現

加入版本號進行更新,只需在url後面加上version引數,如:

PUT http://localhost:9200/blogs/blog/1?version=2

4、刪除操作
通過DELETE操作,可以刪除ES中的資料。HTTP請求如下:

DELETE  http://localhost:9200/blogs/blog/1

該請求成功後伺服器返回的資訊如下:

{
  "found": true,
  "_index": "blogs",
  "_type": "blog",
  "_id": "1",
  "_version": 2,
  "result": "deleted",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  }
}

如果我們這時去執行GET操作,如

GET http://localhost:9200/blogs/blog/1

該請求成功後伺服器返回的資訊如下:

{
  "_index": "blogs",
  "_type": "blog",
  "_id": "1",
  "found": false
}

從響應的結果可以看出,沒有查到資料。

5、搜尋操作
下面我們來看下ES最強大的搜尋操作,首先我們來先插入2條資料,包括前面插入和被刪除的資料。

PUT  http://localhost:9200/blogs/blog/1
{
    "title": "es info",
    "content": "about elasticsearch",
    "author": "jack",
    "year":2018
}

PUT  http://localhost:9200/blogs/blog/2
{
    "title": "zk info",
    "content": "about zookeeper",
    "author": "jack",
    "year":2018
}

下面我們來執行根據給定的字串進行查詢,只要資料中有包含給定字串的內容就認為匹配上,查詢命令如下:

POST http://localhost:9200/_search
{
    "query": {
        "query_string": {
            "query": "elasticsearch"
        }
    }
}

返回的結果如下:

{
  "took": 3,
  "timed_out": false,
  "_shards": {
    "total": 10,
    "successful": 10,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 0.26742277,
    "hits": [
      {
        "_index": "blogs",
        "_type": "blog",
        "_id": "1",
        "_score": 0.26742277,
        "_source": {
          "title": "es info",
          "content": "about elasticsearch",
          "author": "jack",
          "year": 2018
        }
      }
    ]
  }
}

可以看出,搜尋到了資料。我們可以試著改變上面查詢條件中"query"引數的值,來觀察結果的變化。

上面的搜尋是搜尋整個json資料中的資訊,我們也可以只搜尋指定json欄位中的內容。如:

POST http://localhost:9200/_search
{
    "query": {
        "query_string": {
            "query": "jack",
            "fields": ["author"]
        }
    }
}

上面的REST語句表示只在欄位author中查詢存在jack字串的資料。欄位通過查詢條件中的filelds引數指定,可以看出,同時可指定多個欄位。 對比關係資料庫,ES的搜尋操作有點類似關係資料庫中帶like子句的select語句。

可以看出,利用ES的RESTful Api進行操作還是比較簡單的,當然我們只是列舉了幾個最基本的操作。上面通過舉例讓我們站在使用者的角度對ES有了個初步的認識,下面章節繼續展開更為詳細的介紹。

(四)遠端訪問

上面例子中我們都是在本地利用REST介面訪問ES的,即web客戶端執行在ES例項所在的機器上,所以url中用的是localhost。 如果需要支援對ES的遠端訪問,可以修改ES安裝目錄的config/elasticsearch.yml檔案,去掉network.host的註釋,將它的值改成0.0.0.0,然後重新啟動 ES。配置檔案中資訊如:

network.host: 0.0.0.0

上面配置,設成0.0.0.0讓任何一臺機器都可以訪問。線上服務不要這樣設定,要設成具體的 IP,如:

network.host: 192.168.0.1

三、邏輯概念

我們上面的例子使用了 http://localhost:9200/blogs/blog/1 這樣的ulr來進行資料的插入、查詢及搜尋和刪除操作。拋開操作的方式,感覺和關係資料庫的操作有類似的地方。這其實也是正常的,因為資料庫也是用來進行資料儲存和分析(查詢)的,所以從功能上說肯定有很多類似的地方。我們知道關係資料庫有資料庫、表、記錄、欄位等概念,為了更好地理解ES的邏輯架構,我們在介紹ES的一些重要概念的時候會對比關係資料庫中的一些概念

(一)索引(Index)

ES資料管理的頂層單位就叫做 Index(索引)。它不是關係資料庫中索引的概念,是單個數據庫的同義詞,即可以把它等價於關係資料庫中的單個數據庫。Index的名稱必須小寫。

既然Index是ES管理資料的頂層單位,肯定先需要有索引,才能進行後續的資料儲存等操作,類似關係資料庫中得首先有資料庫一樣。可前面的操作我們並沒有看到建立Index的操作。是不是ES啟動後有一個預設的Index呢?

其實情況是這樣的,上面的REST請求 http://localhost:9200/blogs/blog/1 中的 blogs就是一個索引名,當我們執行資料插入操作時,如果url中指定的索引不存在,則ES會自動建立該索引。就如我們前面的例子,我們插入資料時,索引blogs並不存在,所以ES按照預設的設定自動建立了blogs索引。

我們可以單獨建立一個索引,操作如下:

PUT  http://localhost:9200/topics

上面操作通過http的PUT操作,建立了一個名稱為topics的索引。
操作成功後的響應資訊如下:

{
  "acknowledged": true,
  "shards_acknowledged": true,
  "index": "topics"
}

我們可以檢視到ES中的所有索引,操作如下:

GET  http://localhost:9200/_cat/indices?v

響應結果如下:

health  status  index  uuid  pri  rep  docs.count  docs.deleted  store.size   pri.store.size
yellow  open   blogs  hM...  5    1      2          0         10.2kb      10.2kb
yellow  open   topics  hV...  5    1      0          0         810b        810b

結果以表格的形式顯示,第一行為表頭。因為前面的操作我們已經建立了blogs索引,加上剛建立的topics索引,所以我們看到結果有2條記錄。

通過DELETE操作,我們可以刪除指定的索引,如下面操作:

DELETE  http://localhost:9200/topics

操作成功的響應結果如下:

{
  "acknowledged": true
}

這表示刪除索引成功,如果我們這時再去查詢所有索引,會發現topics索引沒有了。

(二)型別(Type)

在索引中,可以定義一個或多個型別(type),型別是索引的邏輯分割槽,是同一索引中有公共欄位的文件的集合。比如在一個部落格系統中,我們可以將使用者資料放到一種型別中,將文章資料放到一種型別中,將對文章的評論資訊放到一種型別中。

型別不需要單獨建立,在插入資料(如上面的例子)會自動建立。對於 http://localhost:9200/blogs/blog/1 這個url,其中的blog就是型別(type)名。

相對關係資料庫來說,型別可以類比成關係資料庫中的表。
需要注意的是,根據規劃,Elastic 6.x 版只允許每個 Index 包含一個 Type,7.x 版將會徹底移除 Type。

所以我們在實際使用中,不用過多考慮Type的作用。

(三)文件(Document)

Document是Index中的單條記錄,它就像關係資料庫中表中的記錄(行)。Document 使用 JSON 格式表示,如上面插入資料時的url後面跟的請求資料:

PUT http://localhost:9200/blogs/blog/1
{
    "title": "es info",
    "content": "about elasticsearch",
    "author": "jack",
    "year":2018
}

ES的每個儲存在Index中的Document都有一個型別(type)和一個唯一的ID。這個ID可以使用者在建立文件時顯示指定,如上面url最後的1,也可以由ES自動生成(後面會介紹)。

JSON資料是一種半結構化的資料格式,它由一個個的欄位組成,欄位有欄位名、欄位的值,和欄位型別,比如上面的title欄位就是一個字串型別,year欄位就是一個整數型別。JSON資料的欄位型別不需要顯示定義,由欄位的內容推斷出來,比如字串是要放到引號中,整數則不能。

同一個 Index 裡面的 Document(即使是位於同一個Type下),不要求有相同的結構(即相同的欄位和欄位型別),但是最好保持相同,這樣有利於提高搜尋效率。需要注意的是,同一個欄位名的欄位,不能在這個文件中是字串型別,而在另外一個字串中是陣列型別。舉個例子,上面舉例中我們插入瞭如下的資料:

PUT http://localhost:9200/blogs/blog/1
{
    "title": "es info",
    "content": "about elasticsearch",
    "author": "jack",
    "year":2018
}

這時如果插入如下資料:

PUT http://localhost:9200/blogs/blog/2
{
    "title": "es info",
    "content": "about elasticsearch",
    "author": "jack",
    "year": "2018年"
}

也就是這裡插入的year欄位值是個字串,則時ES的響應就會報錯,報型別不一致的錯誤,因為前面插入的資料已經讓ES把year欄位認作為整型資料。但如果我們寫成 "year": "2018" 這樣的格式,雖然看上去year欄位是字串型別,但因為實際資料是整數,則不會報錯。

因為即使是同一個Type下的Docuemnt也不要求有相同的資料模型,所以邏輯上Type與關係資料庫的表對應,實際意義差別還是挺大的。在關係資料庫下,表中的每條記錄資料模型都是嚴格相同的。

(四)欄位(Field)

上面已經提到了欄位,欄位就是Docuemnt對應的json內容的欄位。一個Docuemnt可以包括零個或多個欄位,欄位可以是一個簡單的值(如字串、整數、日期),也可以是一個數組或物件的巢狀結構。每個欄位都對應一個數據型別,如整數、字串、陣列、物件等。

(五)對映(mapping)

mapping是類似於資料庫中的表結構定義,主要作用如下:

  • 定義index下的欄位名
  • 定義欄位型別,比如數值型、浮點型、布林型等
  • 定義倒排索引相關的設定,比如是否索引、記錄position等
  • 設定分詞器等

與表結構不同的是,關係資料庫的表的結構必須事先通過create table語句來明確。而對映既可以顯示的通過命令來事先定義,也可以在儲存文件(插入資料)時由ES來自動識別。如我們上面的例子,並沒有顯示的去定義Index的mapping資訊。

可以通過 GET http://localhost:9200/_mapping 來檢視Index的mapping資訊。

(六)主鍵(ID)

ES中的每個Document都有一個唯一的ID(在type下唯一),也就是說 index/type/id必須是唯一的。
我們可以插入資料時顯示的指定ID,如前面的操作:

PUT  http://localhost:9200/blogs/blog/1

也可以也ES系統自動生成,注意這時就不能用PUT操作,要用POST操作,如下面操作:

POST  http://localhost:9200/blogs/blog
{
    "title": "es info",
    "content": "about elasticsearch",
    "author": "jack",
    "year":"2018"
}

上面請求中url的最後沒有指定要插入的Document的ID,操作成功後的響應資訊如下:

{
  "_index": "blogs",
  "_type": "blog",
  "_id": "AWeXZiyTS_34KbUEtT3A",
  "_version": 1,
  "result": "created",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "created": true
}

可以看出,響應資訊中帶回來了ES自動生成的ID值。

關於ELKB

先說下ELK,ELK是一個流行的日誌系統解決方案,注意,ELK不是一個軟體名,而是一個解決方案的縮寫,即Elasticsearch+Logstash+Kibana(ELK Stack)這三個軟體的集合。

這幾個都是開源的java產品,但是眾所周知,java的東西很吃記憶體和CPU,Logstash在作為收集日誌的Agent時,就顯得太過臃腫了。後來官方在logstash-forwarder的基礎上推出了beat系列,裡面包括四個系統,分別是:

1、Packetbeat(蒐集網路流量資料);
2、Topbeat(蒐集系統、程序和檔案系統級別的 CPU 和記憶體使用情況等資料);
3、Filebeat(蒐集檔案資料),Filebeat佔用資源少,適合於在各個伺服器上搜集日誌後傳輸給Logstash;
4、Winlogbeat(蒐集 Windows 事件日誌資料)。

所以Filebeat也就這樣加入了“日誌收集分析”的團隊裡,所以雖然大家還是習慣性的叫ELK,其實準確的說法已經是ELKB了。

ELKB中的幾個軟體的分工如下:

1、Elasticsearch:分散式搜尋和分析引擎,具有高可伸縮、高可靠和易管理等特點。基於 Apache Lucene 構建,能對大容量的資料進行接近實時的儲存、搜尋和分析操作。通常被用作某些應用的基礎搜尋引擎,使其具有複雜的搜尋功能。

2、Logstash:資料收集額外處理和資料引擎。它支援動態的從各種資料來源蒐集資料,並對資料進行過濾、分析、豐富、統一格式等操作,然後儲存到使用者指定的位置。

3、Kibana:資料分析和視覺化平臺。通常與 Elasticsearch 配合使用,對其中資料進行搜尋、分析和以統計圖表的方式展示。

4、FilebeatELK 協議棧的新成員,在需要採集日誌資料的伺服器上安裝 Filebeat,並指定日誌目錄或日誌檔案後,Filebeat 就能讀取資料,迅速傳送到 Logstash 進行解析,亦或直接傳送到 Elasticsearch 進行集中式儲存和分析。