前言:畢設項目還要求加了這個作大數據搜索,正好本身也比較感興趣,就一塊兒來學習學習吧!html
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);
照例來講應該是去扒官網,結果一搜就驚了,這官網也忒得勁兒了吧,居然提供中文版本並且還有中文版本的文檔,友好友好,我看了好長一下子才反應過來本身還有博客要寫.咳咳,上面的內容都是摘自官網順便附一個官網連接: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 (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 格式的代碼就說明已經成功了:
這是一個官方推出的把 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
即表示服務器狀態目前是健康的:
ElasticSearch 是分佈式數據庫,容許多臺服務器協同工做,每臺服務器能夠運行多個實例。單個實例稱爲一個節點(node),一組節點構成一個集羣(cluster)。分片是底層的工做單元,文檔保存在分片內,分片又被分配到集羣內的各個節點裏,每一個分片僅保存所有數據的一部分。
對比咱們比較熟悉的 MySQL 數據庫:
index → db
type → table
document → row
若是咱們要訪問一個文檔元數據應該包括囊括 index/type/id
這三種類型,很好理解。
全部其餘語言可使用 RESTful API 經過端口 9200 和 Elasticsearch 進行通訊,你能夠用你最喜好的 web 客戶端訪問 Elasticsearch 。一個 Elasticsearch 請求和任何 HTTP 請求同樣由若干相同的部件組成:
curl -X<VERB> '<PROTOCOL>://<HOST>:<PORT>/<PATH>?<QUERY_STRING>' -d '<BODY>'
被 < >
標記的部件:
部件名 | 做用 |
---|---|
VERB |
適當的 HTTP 方法 或 謂詞 : GET 、 POST 、 PUT 、 HEAD 或者 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": {} } }
若是對於 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
。其中,index
和 type
都是可選的。
換句話說,爲了搜索電影,能夠對如下任一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 } } } }
過濾的查詢是具備兩個屬性(query
和filter
)的查詢。執行時,它使用過濾器過濾查詢的結果。要完成這樣的查詢還須要添加一個過濾器,要求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 快速上手學習入門教程
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 */ }
UserDao:
import com.wmyskxz.demo.domain.User; import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; public interface UserDao extends ElasticsearchRepository<User, Integer> { }
這裏牢牢是爲了演示,因此就省略 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