探索ES-什麼?你還不知道ES?(一)

前文回顧

以前有講過碎碎念-探索計劃(九),並且也陸續發了9篇關於Spring Boot的探索系列(固然遠遠尚未結束)。一個是由於碎碎念-以終爲始(四)中提到,個人其中一條目標是可以作出一個有價值的產品,因此探索計劃也要擴展一名對將來可以作出一個產品有幫助的新成員ES了。另一個就是公司也使用到了ES,因此要加快輸入和輸出的腳步了。今天就來帶你從小白到入門EShtml

介紹

ES是一個搜索引擎,底層基於LucceeElasticSearch剛開始是由於在倫敦的一個程序員要給老婆搜索菜譜纔開發出來的。東西被創造出來都是由需求驅動的,而後最後這個東西存在的意義是否仍是最初的需求就不必定了。java

環境

eskibana都是5.0.2版本,起碼今天是這個版本的。不過以後可能考慮升級到6.7版本。node

安裝步驟

單節點部署

  1. 下載es和kibana的安裝包,解壓
  2. 修改配置文件 elasticsearch.yml
  • cluster.name:my-application(當前集羣名稱)
  • node.name:node-1(當前節點名稱)
  • network.host:localhost(最好修改成本機IP地址,在集羣環境下localhost可能會有問題)
  • http.port:9200(ES端口)

集羣部署配置

  • discovery.zen.ping.unicast.host:["host1","host2"] (其餘節點的IP地址和本身節點的地址)
  • dicovery.zen.minimum_master_nodes:(node_numbers / 2) + 1

修改JVM內存大小

  1. 修改jvm.options中內存大小 (考慮到性能不要設置太大,要爲os cache預留一部份內存,保證磁盤上面的數據大小和os cache的大小是一致的,不懂沒有關係,後來慢慢講解)

啓動

  1. 啓動 bin/elasticsearch -d (-d表示用守護模式打開)
  2. 訪問查看ES狀態 curl http://localhost:9200 (有些狀況下不能使用localhost,而是必須使用ip;看綁定的地址是什麼,若是顯示指定了IP,那麼必須是IP) 能夠返回結果
{
  "name" : "node-1",
  "cluster_name" : "my-application",
  "cluster_uuid" : "0P_LVzBYS6qVl8Wo9o817Q",
  "version" : {
    "number" : "5.0.2",
    "build_hash" : "f6b4951",
    "build_date" : "2016-11-24T10:07:18.101Z",
    "build_snapshot" : false,
    "lucene_version" : "6.2.1"
  },
  "tagline" : "You Know, for Search"
}
複製代碼

Kibana安裝

雖然能夠不安裝Kibana,可是通常安轉完ElasticSearch都會安裝Kibana。(以後講解詳細安裝kibana詳細步驟)程序員

查看狀態

安裝完ES以後,通常人確定會想要知道一些ES的狀態基本信息,就好像安裝完數據庫以後,就想要知道這個數據庫安裝在哪一個ip地址,裏面有多少張表,表佔用了多少空間等等基本信息。那麼對於ES來講就是下面幾點。算法

查看健康狀態

查看健康狀態實際上是和ES分片有沒有被分配有關係。存在主分片沒有被分配是Red。主分片已經被分配,可是副本分片沒有被分配是Yellow。剛開始學習最多見的Yellow狀況就是ES只啓動了一個節點,副本分片不能和主分片在同一個節點上,致使副本分片沒法被分配。 主分片和副本分片都分配的狀況下,集羣纔是Green。sql

GET _cat/health?v&pretty
複製代碼

查看節點狀態

看完了集羣的健康狀態以後,能夠查看每個節點的詳細信息,內存使用狀況,cpu的使用狀況等數據庫

GET /_cat/nodes?v
複製代碼

參考 cat-nodesjson

查看ES狀態所有索引

查看索引的存在狀態bash

GET _cat/indices?v&pretty
複製代碼

查看ES節點配置信息

GET _nodes?pretty
複製代碼

查看分片信息

能夠查看某個特定索引的分片狀況,狀態、在哪一個節點等網絡

GET _cat/shards/indexName*?pretty&v
複製代碼

通常默認的好像不全面,可使用下面這個語句。

GET _cat/shards?h=index,shard,prirep,state,unassigned.*&pretty&v
複製代碼

經過這個語句能夠看到分片級別的狀態,我發現ES有些API也不是很好。indices這個API都沒有說明沒有分片的個數。可是health裏面又存在整個集羣下沒有分片的個數。

分析分片沒有被分配緣由

GET /_cluster/allocation/explain
{
  "index":"bank",
  "shard":0,
  "primary":false
}
複製代碼

基本概念

Node

節點。每一個ES實例都是一個節點。能夠對每一個啓動的ES節點設置一個惟一的節點名稱,在elasticsearch.ymlnode.name字段來指定。在ES中節點存在不一樣的類型,首先數據節點是存儲數據的。每次一個請求進來,由於每個節點都擁有協調能力,在請求進來的時候,節點自動成爲協調節點。

另外還有master節點和數據節點。master節點存儲了ES集羣的元信息。當請求進入到master節點時,master節點根據hash算法和分片信息,將請求打入到對應的分片上面。

Cluster

集羣。多個ES節點能夠組成一個集羣。只要節點的集羣名字相同便可。在elasticsearch.ymlcluster.name來指定。只要cluster.name相同,那麼在節點之間網絡連通的狀況下,多個節點會自動組成一個集羣。

Index

index就是ES的索引,簡單理解爲Mysql的數據庫。一個ES節點能夠有多個索引。

Type

索引的類型。簡單理解爲Mysql的表。對一個索引進行邏輯上面的區分。一個索引下面能夠有多個type。

Document

文檔。至關於數據庫裏面的記錄。一個type下面能夠多個文檔。

Shards And Replicas

分片和副本。一個索引默認會有5個分片和1個備份,會產生5個主分片和5個備份分片。5個分片會分散到集羣中不一樣的節點上面,另外須要注意的是主分片和副本分片必定不能再同一個節點上。若是有多個副本分片,相同數據的副本分片也不能在同一個節點上面。否則會致使分片沒有被分配。

Replica是ES實現高可用的一種方式,以後會進行深刻的擴展。

也可能會遇到一些問題?好比ES沒有分配分片?以後會有文章會講到故障的排查。

建表、創建索引

跟數據庫同樣,要使用數據庫首先要建庫,在ES裏面就是創建索引。索引index至關於數據庫,type至關於表,id至關於文檔的主鍵。

PUT /people?pretty
複製代碼

而後可使用查詢所有索引的語句查看,能夠發現多了一條記錄。

ES與關係型數據庫不一樣的地方在於ES是能夠動態增長字段的。 因此,建索引(建表)的時候能夠不指定全部的字段,當有新的字段存在時,可使用動態映射的方式(dymatic mapping)來指定字段類型。

要注意的點是一個新的字段是什麼類型只有在第一次這個字段進去到ES時會被指定,其餘時候不會被指定。

查看節點狀態可以看到只是yellow,由於當前只有一個節點,副本分片不能和主分片在同一個節點上,致使副本分片沒有被分配,沒有實現高可用。

epoch      timestamp cluster        status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent
1554208915 20:41:55  my-application yellow          1         1      6   6    0    0        6             0                  -                 50.0%
複製代碼
  • docs.count:表示該索引下面全部的文檔數

插入ES操做

有了索引以後,可使用Restful接口插入數據到ES中。使用下面的語句創建。

PUT /people/info/1?pretty
{
  "name": "John Doe"
}
複製代碼

這裏的1就是建立的新文檔的id,能夠指定也能夠不指定。建議不指定,會快一些。成功以後提示以下。

{
  "_index": "people",
  "_type": "info",
  "_id": "1",
  "_version": 1,
  "result": "created",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "created": true
}
複製代碼

這裏使用的是PUT指令,表示更新指定的文檔。由於是更新指定的文檔,因此這裏第三個參數1是必須填寫的。ES的更新文檔的操做實際上是會判斷文檔存不存在,若是不存在那麼就是新建一條新的文檔。若是想要直接真正新建一條文檔,並且這種狀況下也不須要填寫id,能夠直接新增,可使用POST方式,以下。

POST /people/info?pretty
{
  "name": "John Doe"
}
複製代碼

返回格式以下。

{
  "_index": "people",
  "_type": "info",
  "_id": "AWnjMpZuDCZ3hLyrI_RF",
  "_version": 1,
  "result": "created",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "created": true
}
複製代碼

還可使用bulk來批量插入數據,以下所示。要注意的是bulk對於json的格式有嚴格的要求,每個完整的json只能是一行,不能多行。而已一個完整json以後必須換行。

bulk還能夠這樣寫

POST /customer/external/_bulk?pretty
{"index":{"_id":"1"}}
{"name": "John Doe" }
{"index":{"_id":"2"}}
{"name": "Jane Doe" }
複製代碼

ES查詢

那麼如今測試數據都進入了ES,如何查詢呢?通常人可能會有兩種查詢需求,一種是查詢某個索引下面全部的數據,一種是根據id來查詢,另外就是根據某一個具體的字段來查詢。一個一個來看。 首先全部的查詢都必須加上_search字段在請求的末尾。

  • 查詢索引下面所有的文檔。只要在須要查詢的index後面加上_search就行了。
GET /people/_search
複製代碼

也能夠這樣寫。

GET /people/_search
{
  "query": { "match_all": {} }
}
複製代碼

返回以下。

{
  "took": 2,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 6,
    "max_score": 1,
    "hits": [
      {
        "_index": "people",
        "_type": "info",
        "_id": "AWnjMpZuDCZ3hLyrI_RF",
        "_score": 1,
        "_source": {
          "name": "John Doe"
        }
      },
      .....省略後面5條數據
複製代碼
  • 根據某一個字段來查詢,使用match查詢。
GET /people/_search
{
  "query": {
    "match": {
      "name": "John"
    }
  }
}
複製代碼

這裏就是搜索全部name中含有John的文檔。這裏的含有就是指定的字段必須是全文索引的。 可是想要精確地搜索nameJohn的文檔。就可使用term查詢,而不是match查詢。

POST _search
{
  "query": {
    "term" : { "name" : "John" } 
  }
}
複製代碼

ES更新文檔

PUT /people/info/1?pretty
{
  "name": "John Doe"
}
複製代碼

經過上面這個更新的語句就能夠將文檔更新。可是這裏重點要講一下,這個更新操做是覆蓋更新。在ES的底層,更新操做會先找到這條ES數據,而後用新的ES數據給徹底覆蓋掉這條數據。

可是每每有時候咱們想要實現的是增量更新,那麼應該怎麼辦呢?

PUT /people/info/1/_update
{
"doc":{
"name":"Mike"
}
}
複製代碼

經過這種方式就能夠將某一個文檔增量更新了。可是若是要刪除某一個文檔裏面的一個字段,應該只能用全量的方式了吧。注意這裏的語法必定要加上doc,url上面要加上_update。

查詢所有文檔

GET _search
{
  "query": {
    "match_all": {}
  }
}
複製代碼

全部的命令能夠總結爲<REST Verb> /<Index>/<Type>/<ID>

排序

POST /_search
{
   "query" : {
      "term" : { "product" : "chocolate" }
   },
   "sort" : [
      {"price" : {"order" : "asc"}}
   ]
}
複製代碼

聚合操做

ES不只提供了數據的搜索還提供了數據的檢索,聚合。下面就來聊一聊聚合操做。

簡單聚合

先來個簡單的聚合操做。 首先下載app.json的原始數據。需求是按state來分組計算出分組中document的數量,而後計算分組內金額的平均數。size:0表示不會返回命中的document,只是返回分組,在ES中分組又被稱之爲桶bucket,默認返回10個桶。

GET /bank/_search
{
  "size": 0,
  "aggs": {
    "group_by_state": {
      "terms": {
        "field": "state.keyword"
      },
      "aggs": {
        "average_balance77": {
          "avg": {
            "field": "balance"
          }
        }
      }
    }
  }
}
複製代碼

獲得以下結果

{
  "took": 75,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 1000,
    "max_score": 0,
    "hits": []//size:0,所示hits不展現
  },
  "aggregations": {
    "group_by_state": {
      "doc_count_error_upper_bound": 20,
      "sum_other_doc_count": 770,
      "buckets": [//第一個bucket
        {
          "key": "ID",
          "doc_count": 27,
          "average_balance77": {//balance平均數
            "value": 24368.777777777777
          }
        },
        {//第二個bucket
          "key": "TX",
          "doc_count": 27,
          "average_balance77": {//balance平均數
            "value": 27462.925925925927
          }
        },
複製代碼

嵌套聚合

看過簡單的聚合以後,是否是火燒眉毛想要看看複雜的聚合操做呢?先上例子。

GET /bank/_search
{
  "size": 0,
  "aggs": {
    "group_by_age": {
      "range": {
        "field": "age",
        "ranges": [
          {
            "from": 20,
            "to": 30
          },
          {
            "from": 30,
            "to": 40
          },
          {
            "from": 40,
            "to": 50
          }
        ]
      },
      "aggs": {
        "group_by_gender": {
          "terms": {
            "field": "gender.keyword"
          },
          "aggs": {
            "average_balance": {
              "avg": {
                "field": "balance"
              }
            }
          }
        }
      }
    }
  }
}
複製代碼

其實就是聚合以後能夠再次對於已經聚合以後的數據進行聚合操做。就好像sql中group by以後,再對group by以後的數據再次進行group by操做。分桶以後能夠再次分桶。

小結

好了,看完了上文,關於ES的安裝、部署、查詢、更新、聚合等基本操做都掌握了嗎?

關於寫做

之後這裏天天都會寫一篇文章,題材不限,內容不限,字數不限。儘可能把本身天天的思考都放入其中。

若是這篇文章給你帶來了一些幫助,能夠動動手指點個贊,順便關注一波就更好了。

若是上面都沒有,那麼寫下讀完以後最想說的話?有效的反饋和你的鼓勵是對我最大的幫助。

另外打算把博客給從新撿起來了。歡迎你們來訪問吃西瓜

我是shane。今天是2019年8月16日。百天寫做計劃的第二十三天,23/100。

相關文章
相關標籤/搜索