Elasticsearch【快速入門】

前言:畢設項目還要求加了這個作大數據搜索,正好本身也比較感興趣,就一塊兒來學習學習吧!html

Elasticsearch 簡介

Elasticsearch 是一個分佈式、RESTful 風格的搜索和數據分析引擎,可以解決不斷涌現出的各類用例。做爲 Elastic Stack 的核心,它集中存儲您的數據,幫助您發現意料之中以及意料以外的狀況。java

查詢

保持好奇心。從數據中探尋各類問題的答案。node

經過 Elasticsearch,您可以執行及合併多種類型的搜索(結構化數據、非結構化數據、地理位置、指標),搜索方式隨心而變。先從一個簡單的問題出發,試試看可以從中發現些什麼。git

分析

大處着眼,全局在握。github

找到與查詢最匹配的十個文檔是一回事。但若是面對的是十億行日誌,又該如何解讀呢?Elasticsearch 聚合讓您可以從大處着眼,探索數據的趨勢和模式。web

速度

可擴展性

彈性

靈活性

操做的樂趣

客戶端庫

使用您本身的編程語言與 Elasticsearch 進行交互spring

Elasticsearch 使用的是標準的 RESTful 風格的 API 和 JSON。此外,咱們還構建和維護了不少其餘語言的客戶端,例如 Java、Python、.NET、SQL 和 PHP。與此同時,咱們的社區也貢獻了不少客戶端。這些客戶端使用起來簡單天然,並且就像 Elasticsearch 同樣,不會對您的使用方式進行限制。數據庫

Java:編程

RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(
                    new HttpHost("localhost", 9200, "http")));
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.matchAllQuery());            
searchSourceBuilder.aggregation(AggregationBuilders.terms("top_10_states").field("state").size(10));
SearchRequest searchRequest = new SearchRequest();
searchRequest.indices("social-*");
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = client.search(searchRequest);

盡享強大功能

HADOOP 和 SPRAK

照例來講應該是去扒官網,結果一搜就驚了,這官網也忒得勁兒了吧,居然提供中文版本並且還有中文版本的文檔,友好友好,我看了好長一下子才反應過來本身還有博客要寫.咳咳,上面的內容都是摘自官網順便附一個官網連接:https://www.elastic.co/cn/products/elasticsearchjson

另外還有一個關於 Elasticsearch 來源頗有趣的故事在這裏分享一下:

回憶時光

許多年前,一個剛結婚的名叫 Shay Banon 的失業開發者,跟着他的妻子去了倫敦,他的妻子在那裏學習廚師。 在尋找一個賺錢的工做的時候,爲了給他的妻子作一個食譜搜索引擎,他開始使用 Lucene 的一個早期版本。

直接使用 Lucene 是很難的,所以 Shay 開始作一個抽象層,Java 開發者使用它能夠很簡單的給他們的程序添加搜索功能。 他發佈了他的第一個開源項目 Compass。

後來 Shay 得到了一份工做,主要是高性能,分佈式環境下的內存數據網格。這個對於高性能,實時,分佈式搜索引擎的需求尤其突出, 他決定重寫 Compass,把它變爲一個獨立的服務並取名 Elasticsearch。

第一個公開版本在2010年2月發佈,今後之後,Elasticsearch 已經成爲了 Github 上最活躍的項目之一,他擁有超過300名 contributors(目前736名 contributors )。 一家公司已經開始圍繞 Elasticsearch 提供商業服務,並開發新的特性,可是,Elasticsearch 將永遠開源並對全部人可用。

聽說,Shay 的妻子還在等着她的食譜搜索引擎…

安裝 Elasticsearch

官網最新版本 Elasticsearch (6.5.4),可是因爲本身的環境使用最新版本的有問題(配合下面的工具 Kibana 有問題..Kibana 啓動不了),因此不得不換成更低版本的 6.2.2,下載外鏈:戳這裏,固然你也能夠試一下最新的版本:

順帶一提:在下載以前你應該確保你的 Java 版本保持在 1.8 及以上(就 1.8 吧..),這是 Elasticsearch 的硬性要求,能夠自行打開命令行輸入 java -version 來查看 Java 的版本

下載完成後,能夠看到是一個壓縮包,咱們直接解壓在 D 盤上,而後打開 bin 目錄下的 elasticsearch.bat 文件

等待一段時間後,能夠看到小黑框輸出一行 start ,就說明咱們的 Elasticsearch 已經跑起來了,咱們訪問地址:http://127.0.0.1:9200/,看到返回一串 JSON 格式的代碼就說明已經成功了:

安裝 Kibana

這是一個官方推出的把 Elasticsearch 數據可視化的工具,官網在這裏:【傳送門】,不過咱們如今暫時還用不到那些數據分析的東西,不過裏面有一個 Dev Tools 的工具能夠方便的和 Elasticsearch 服務進行交互,去官網下載了最新版本的 Kibana(6.5.4) 結果不知道爲何老是啓動不起來,因此換一了一個低版本的(6.2.2)正常,給個下載外鏈:下載點這裏,大家也能夠去官網試試能不能把最新的跑起來:

解壓到 D 盤(意外的有點慢..),一樣打開目錄下的bin\kibana.bat

等待一段時間後就能夠看到提示信息,運行在 5601 端口,咱們訪問地址 http://localhost:5601/app/kibana#/dev_tools/console?_g=() 能夠成功進入到 Dev-tools 界面:

點擊 【Get to work】,而後在控制檯輸入 GET /_cat/health?v 查看服務器狀態,能夠在右側返回的結果中看到 green 即表示服務器狀態目前是健康的:


快速入門

1、基礎概念-快速入門

節點 Node、集羣 Cluster 和分片 Shards

ElasticSearch 是分佈式數據庫,容許多臺服務器協同工做,每臺服務器能夠運行多個實例。單個實例稱爲一個節點(node),一組節點構成一個集羣(cluster)。分片是底層的工做單元,文檔保存在分片內,分片又被分配到集羣內的各個節點裏,每一個分片僅保存所有數據的一部分。

索引 Index、類型 Type 和文檔 Document

對比咱們比較熟悉的 MySQL 數據庫:

index → db
type → table
document → row

若是咱們要訪問一個文檔元數據應該包括囊括 index/type/id 這三種類型,很好理解。

2、使用 RESTful API 與 Elasticsearch 進行交互

全部其餘語言可使用 RESTful API 經過端口 9200 和 Elasticsearch 進行通訊,你能夠用你最喜好的 web 客戶端訪問 Elasticsearch 。一個 Elasticsearch 請求和任何 HTTP 請求同樣由若干相同的部件組成:

curl -X<VERB> '<PROTOCOL>://<HOST>:<PORT>/<PATH>?<QUERY_STRING>' -d '<BODY>'

< > 標記的部件:

部件名 做用
VERB 適當的 HTTP 方法 或 謂詞 : GETPOSTPUTHEAD 或者 DELETE
PROTOCOL http 或者 https(若是你在 Elasticsearch 前面有一個 https 代理)
HOST Elasticsearch 集羣中任意節點的主機名,或者用 localhost 表明本地機器上的節點。
PORT 運行 Elasticsearch HTTP 服務的端口號,默認是 9200
PATH API 的終端路徑(例如 _count 將返回集羣中文檔數量)。Path 可能包含多個組件,例如:_cluster/stats_nodes/stats/jvm
QUERY_STRING 任意可選的查詢字符串參數 (例如 ?pretty 將格式化地輸出 JSON 返回值,使其更容易閱讀)
BODY 一個 JSON 格式的請求體 (若是請求須要的話)

就好比計算集羣中文檔的數量,咱們能夠用這個:

curl -XGET 'http://localhost:9200/_count?pretty' -d '
{
    "query": {
        "match_all": {}
    }
}
'

不過對於安裝了 Kibana 的咱們,能夠直接在 Kibana 的控制檯輸出如下語句,也是一樣的效果:

GET /_count?pretty
{
    "query": {
        "match_all": {}
    }
}

文檔管理(CRUD)

若是對於 RESTful 不太熟悉的童鞋請右轉:【傳送門】

增長:

POST /db/user/1
{
  "username": "wmyskxz1",
  "password": "123456",
  "age": "22"
}
POST /db/user/2
{
  "username": "wmyskxz2",
  "password": "123456",
  "age": "22"
}

這一段代碼稍微解釋一下,這其實就往索引爲 db 類型爲 user 的數據庫中插入一條 id 爲 1 的一條數據,這條數據其實就至關於一個擁有 username/password/age 三個屬性的一個實體,就是 JSON 數據

執行命令後,Elasticsearch 返回以下數據:

# POST /db/user/1
{
  "_index": "db",
  "_type": "user",
  "_id": "1",
  "_version": 1,
  "result": "created",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "_seq_no": 2,
  "_primary_term": 1
}

# POST /db/user/2
{
  "_index": "db",
  "_type": "user",
  "_id": "2",
  "_version": 1,
  "result": "created",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "_seq_no": 1,
  "_primary_term": 1
}

version 是版本號的意思,當咱們執行操做會自動加 1

刪除:

DELETE /db/user/1

Elasticsearch 返回數據以下:

{
  "_index": "db",
  "_type": "user",
  "_id": "1",
  "_version": 2,
  "result": "deleted",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "_seq_no": 1,
  "_primary_term": 1
}

這裏就能夠看到 version 變成了 2

修改:

PUT /db/user/2
{
  "username": "wmyskxz3",
  "password": "123456",
  "age": "22"
}

Elasticsearch 返回數據以下:

{
  "_index": "db",
  "_type": "user",
  "_id": "2",
  "_version": 2,
  "result": "updated",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "_seq_no": 2,
  "_primary_term": 1
}

查詢:

GET /db/user/2

返回數據以下:

{
  "_index": "db",
  "_type": "user",
  "_id": "2",
  "_version": 2,
  "found": true,
  "_source": {
    "username": "wmyskxz3",
    "password": "123456",
    "age": "22"
  }
}

搜索

上面咱們已經演示了基本的文檔 CRUD 功能,然而 Elasticsearch 的核心功能是搜索,因此在學習以前,爲更好的演示這個功能,咱們先往 Elasticsearch 中插入一些數據:

PUT /movies/movie/1
{
  "title": "The Godfather",
  "director": "Francis Ford Coppola",
  "year": 1972,
  "genres": [
    "Crime",
    "Drama"
  ]
}

PUT /movies/movie/2
{
  "title": "Lawrence of Arabia",
  "director": "David Lean",
  "year": 1962,
  "genres": [
    "Adventure",
    "Biography",
    "Drama"
  ]
}

PUT /movies/movie/3
{
  "title": "To Kill a Mockingbird",
  "director": "Robert Mulligan",
  "year": 1962,
  "genres": [
    "Crime",
    "Drama",
    "Mystery"
  ]
}

PUT /movies/movie/4
{
  "title": "Apocalypse Now",
  "director": "Francis Ford Coppola",
  "year": 1979,
  "genres": [
    "Drama",
    "War"
  ]
}

PUT /movies/movie/5
{
  "title": "Kill Bill: Vol. 1",
  "director": "Quentin Tarantino",
  "year": 2003,
  "genres": [
    "Action",
    "Crime",
    "Thriller"
  ]
}

PUT /movies/movie/6
{
  "title": "The Assassination of Jesse James by the Coward Robert Ford",
  "director": "Andrew Dominik",
  "year": 2007,
  "genres": [
    "Biography",
    "Crime",
    "Drama"
  ]
}

**_search端點**

如今已經把一些電影信息放入了索引,能夠經過搜索看看是否可找到它們。 爲了使用 ElasticSearch 進行搜索,咱們使用 _search 端點,可選擇使用索引和類型。也就是說,按照如下模式向URL發出請求:<index>/<type>/_search。其中,indextype 都是可選的。

換句話說,爲了搜索電影,能夠對如下任一URL進行POST請求:

搜索請求正文和ElasticSearch查詢DSL

若是隻是發送一個請求到上面的URL,咱們會獲得全部的電影信息。爲了建立更有用的搜索請求,還須要向請求正文中提供查詢。 請求正文是一個JSON對象,除了其它屬性之外,它還要包含一個名稱爲 「query」 的屬性,這就可以使用ElasticSearch的查詢DSL。

{
    "query": {
        //Query DSL here
    }
}

你可能想知道查詢DSL是什麼。它是ElasticSearch本身基於JSON的域特定語言,能夠在其中表達查詢和過濾器。你能夠把它簡單同SQL對應起來,就至關因而條件語句吧。

基本自由文本搜索:

查詢DSL具備一長列不一樣類型的查詢可使用。 對於「普通」自由文本搜索,最有可能想使用一個名稱爲「查詢字符串查詢」。

查詢字符串查詢是一個高級查詢,有不少不一樣的選項,ElasticSearch將解析和轉換爲更簡單的查詢樹。若是忽略了全部的可選參數,而且只須要給它一個字符串用於搜索,它能夠很容易使用。

如今嘗試在兩部電影的標題中搜索有「kill」這個詞的電影信息:

GET /_search
{
  "query": {
    "query_string": {
      "query": "kill"
    }
  }
}

執行上面的請求並查看結果,以下所示 -

正如預期的,獲得兩個命中結果,每一個電影的標題中都帶有「kill」單詞。再看看另外一種狀況,在特定字段中搜索。

指定搜索的字段

在前面的例子中,使用了一個很是簡單的查詢,一個只有一個屬性 「query」 的查詢字符串查詢。 如前所述,查詢字符串查詢有一些能夠指定設置,若是不使用,它將會使用默認的設置值。

這樣的設置稱爲「fields」,可用於指定要搜索的字段列表。若是不使用「fields」字段,ElasticSearch查詢將默認自動生成的名爲 「_all」 的特殊字段,來基於全部文檔中的各個字段匹配搜索。

爲了作到這一點,修改之前的搜索請求正文,以便查詢字符串查詢有一個 fields 屬性用來要搜索的字段數組:

GET /_search
{
  "query": {
    "query_string": {
      "query": "ford",
      "fields": [
        "title"
      ]
    }
  }
}

執行上面查詢它,看看會有什麼結果(應該只匹配到 1 行數據):

正如預期的獲得一個命中,電影的標題中的單詞「ford」。如今,從查詢中移除fields屬性,應該能匹配到 3 行數據:

過濾

前面已經介紹了幾個簡單的自由文本搜索查詢。如今來看看另外一個示例,搜索 「drama」,不明確指定字段,以下查詢 -

GET /_search
{
  "query": {
    "query_string": {
      "query": "drama"
    }
  }
}

由於在索引中有五部電影在 _all 字段(從類別字段)中包含單詞 「drama」,因此獲得了上述查詢的 5 個命中。 如今,想象一下,若是咱們想限制這些命中爲只是 1962 年發佈的電影。要作到這點,須要應用一個過濾器,要求 「year」 字段等於 1962。要添加過濾器,修改搜索請求正文,以便當前的頂級查詢(查詢字符串查詢)包含在過濾的查詢中:

{
    "query": {
        "filtered": {
            "query": {
                "query_string": {
                    "query": "drama"
                }
            },
            "filter": {
                //Filter to apply to the query
            }
        }
    }
}

過濾的查詢是具備兩個屬性(queryfilter)的查詢。執行時,它使用過濾器過濾查詢的結果。要完成這樣的查詢還須要添加一個過濾器,要求year字段的值爲1962

ElasticSearch查詢DSL有各類各樣的過濾器可供選擇。對於這個簡單的狀況,某個字段應該匹配一個特定的值,一個條件過濾器就能很好地完成工做。

"filter": {
    "term": { "year": 1962 }
}

完整的搜索請求以下所示:

GET /_search
{
  "query": {
    "filtered": {
      "query": {
        "query_string": {
          "query": "drama"
        }
      },
      "filter": {
        "term": {
          "year": 1962
        }
      }
    }
  }
}

當執行上面請求,只獲得兩個命中,這個兩個命中的數據的 year 字段的值都是等於 1962

無需查詢便可進行過濾

在上面的示例中,使用過濾器限制查詢字符串查詢的結果。若是想要作的是應用一個過濾器呢? 也就是說,咱們但願全部電影符合必定的標準。

在這種狀況下,咱們仍然在搜索請求正文中使用 「query」 屬性。可是,咱們不能只是添加一個過濾器,須要將它包裝在某種查詢中。

一個解決方案是修改當前的搜索請求,替換查詢字符串 query 過濾查詢中的 match_all 查詢,這是一個查詢,只是匹配一切。相似下面這個:

GET /_search
{
  "query": {
    "filtered": {
      "query": {
        "match_all": {}
      },
      "filter": {
        "term": {
          "year": 1962
        }
      }
    }
  }
}

另外一個更簡單的方法是使用常數分數查詢:

GET /_search
{
  "query": {
    "constant_score": {
      "filter": {
        "term": {
          "year": 1962
        }
      }
    }
  }
}

參考文章:Elasticsearch入門教程Elasticsearch官方文檔ElasticSearch 快速上手學習入門教程

3、集成 SpringBoot 簡單示例

第一步:新建 SpringBoot 項目

pom包依賴:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
<!-- Elasticsearch支持 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>

application.properties:

spring.data.elasticsearch.cluster-nodes=127.0.0.1:9300

第二步:新建實體類

User類:

@Document(indexName = "users", type = "user")
public class User {
    private int id;
    private String username;
    private String password;
    private int age;

    /** getter and setter */
}

第三步:Dao 層

UserDao:

import com.wmyskxz.demo.domain.User;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

public interface UserDao extends ElasticsearchRepository<User, Integer> {
}

第四步:Controller 層

這裏牢牢是爲了演示,因此就省略 service 層,固然 CRUD 不能少:

@RestController
public class UserController {
    @Autowired
    UserDao userDao;

    @PostMapping("/addUser")
    public String addUser(String username, String password, Integer age) {
        User user = new User();
        user.setUsername(username);
        user.setPassword(password);
        user.setAge(age);
        return String.valueOf(userDao.save(user).getId());// 返回id作驗證
    }

    @DeleteMapping("/deleteUser")
    public String deleteUser(Integer id) {
        userDao.deleteById(id);
        return "Success!";
    }

    @PutMapping("/updateUser")
    public String updateUser(Integer id, String username, String password, Integer age) {
        User user = new User();
        user.setId(id);
        user.setUsername(username);
        user.setPassword(password);
        user.setAge(age);
        return String.valueOf(userDao.save(user).getId());// 返回id作驗證
    }

    @GetMapping("/getUser")
    public User getUser(Integer id) {
        return userDao.findById(id).get();
    }

    @GetMapping("/getAllUsers")
    public Iterable<User> getAllUsers() {
        return userDao.findAll();
    }
}

第五步:測試

使用 REST 測試工具測試沒有問題,過程我就不給了..bingo!

總結

其實使用 SpringBoot 來操做 Elasticsearch 的話使用方法有點相似 JPA 了,並且徹底能夠把 Elasticsearch 當作 SQL 服務器來用,也沒有問題...在各類地方看到了各個大大特別是官方,都快把 Elasticsearch 這款工具吹上天了,對於它方便的集成這一點我卻是有感覺,關於速度這方面尚未很深的感覺,慢慢來吧...


按照慣例黏一個尾巴:

歡迎轉載,轉載請註明出處!
簡書ID:@我沒有三顆心臟
github:wmyskxz 歡迎關注公衆微信號:wmyskxz 分享本身的學習 & 學習資料 & 生活 想要交流的朋友也能夠加qq羣:3382693

相關文章
相關標籤/搜索