Neil Zhu,簡書ID Not_GOD,University AI 創(chuàng)始人 & Chief Scientist,致力于推進世界人工智能化進程逗堵。制定并實施 UAI 中長期增長戰(zhàn)略和目標力喷,帶領(lǐng)團隊快速成長為人工智能領(lǐng)域最專業(yè)的力量刽漂。
作為行業(yè)領(lǐng)導(dǎo)者,他和UAI一起在2014年創(chuàng)建了TASA(中國最早的人工智能社團), DL Center(深度學(xué)習(xí)知識中心全球價值網(wǎng)絡(luò))弟孟,AI growth(行業(yè)智庫培訓(xùn))等贝咙,為中國的人工智能人才建設(shè)輸送了大量的血液和養(yǎng)分。此外拂募,他還參與或者舉辦過各類國際性的人工智能峰會和活動庭猩,產(chǎn)生了巨大的影響力,書寫了60萬字的人工智能精品技術(shù)內(nèi)容陈症,生產(chǎn)翻譯了全球第一本深度學(xué)習(xí)入門書《神經(jīng)網(wǎng)絡(luò)與深度學(xué)習(xí)》蔼水,生產(chǎn)的內(nèi)容被大量的專業(yè)垂直公眾號和媒體轉(zhuǎn)載與連載。曾經(jīng)受邀為國內(nèi)頂尖大學(xué)制定人工智能學(xué)習(xí)規(guī)劃和教授人工智能前沿課程录肯,均受學(xué)生和老師好評趴腋。
探索elasticsearch
by Andrew Cholakian
相比較官方文檔,這本書很好看论咏。
第二章 建模數(shù)據(jù)
2.1 文檔和字段的基礎(chǔ)知識
在elasticsearch中的最小獨立單元是字段(field)优炬,字段有一個已定義的類型(type),并且擁有一個或者多個該類型的值厅贪。字段包含一個簡單的數(shù)據(jù)塊蠢护,如數(shù)字42
或者字符串"Hello, World!"
,亦或一個同樣類型數(shù)據(jù)的簡單表(single list)养涮,如[5,6,7,8]
葵硕。
文檔(document)是字段的聚合(collection),并且包含了elasticsearch中的基本存儲單元贯吓,就像在傳統(tǒng)的RDBMS中的行(row)那樣懈凹。將文檔作為一個基本的存儲單元的原因是,與Lucene不同的是悄谐,所有完全更新的字段重寫一個給定的文檔進存儲設(shè)備(同時保留哪些沒有變更的字段)蘸劈。所以,當我們從一個API角度看尊沸,字段是最小的單元,而文檔則是從存儲角度的最小單元贤惯。
2.1.1 JSON——ES的語言
在ES中洼专,所有的文檔必須為合法的JSON值。例如
{
"_id": 1,
"handle": "ron",
"age": 28,
"hobbies": ["hacking", "the great outdoors"],
"computer": {"cpu": "pentium pro", "mhz": 200}
}
Elasticsearch reserves some fields for special use. We’ve specified one of these fields in this example: the _id
field. A document’s id is unique, and if unassigned will be created automatically. An elasticsearch id would be a primary key in RDBMS parlance.
While elasticsearch deals with JSON exclusively, internally, the JSON is converted to flat fields for Lucene’s key/value API. Arrays in documents are mapped to Lucene multi-values.
2.2 基本類型
2.2.1 概述
每個ES中的文檔肯定要遵循一個用戶定義的類型映射孵构,類似于數(shù)據(jù)庫的模式(schema)屁商。一個類型的映射同時包含了字段的類型(integer、string……)和這些屬性將被如何索引的方式(這較復(fù)雜的部分在后面會介紹)。
多個在一個索引的文檔可能擁有相同的ID只要這些文檔的類型是不同的蜡镶。
類型使用Mapping API定義雾袱,其將type name和property定義進行關(guān)聯(lián)。圖2.1最小版本的映射如下:
{
"user": {
"properties": {
"handle": {"type": "string"},
"age": {"type": "integer"},
"hobbies": {"type": "string"},
"computer": {
"properties": {
"cpu": {"type": "string"},
"speed": {"type": "integer"}}}}}}
這里相當于數(shù)據(jù)庫模式的定義
2.2.2 數(shù)據(jù)類型
在一個mapping的屬性部分官还,每個字段都與一個不同的core類型關(guān)聯(lián)芹橡。合法的core數(shù)據(jù)類型如下表所示。除了關(guān)聯(lián)數(shù)據(jù)類型到字段外望伦,類型映射定義了諸如analysis設(shè)定和默認的boosting值的屬性林说;后續(xù)章節(jié)會介紹。
Type | Definition |
---|---|
string | Text |
integer | 32 bit integers |
long | 64 bit integers |
float | IEEE float |
double | Double precision floats |
boolean | true or false |
date | UTC Date/Time (JodaTime) |
geo_point | Latitude / Longitude |
2.2.3 數(shù)組屯伞,對象和高級類型
復(fù)雜JSON類型同樣被ES支持腿箩,使用數(shù)組和對象表示。另外的劣摇,ES文檔可以處理更加復(fù)雜的關(guān)系珠移,諸如parent/child關(guān)系,和一個嵌套的聞到那個類型末融。
注意ES中數(shù)組不支持混合類型的元素钧惧。如果一個field被聲明為一個整數(shù),它可以存儲一個或者多個整數(shù)滑潘,不過不能參雜其他類型的元素垢乙。
An important thing to remember, however, is that elasticsearch arrays cannot store mixed types. If a field is declared as an integer, it can store one or many integers, but never a mix of types.
As seen in figure 2.2, mappings may describe objects which contain other objects, as in the computer field in that figure. The key thing to remember with these objects is that their properties are declared in the properties field in the mapping, and that the type field is omitted.
當使用對象的時候,type字段被省略语卤。
子對象仍然存儲在同樣的物理文檔中追逮。所以,還有一個特殊的nested
類型粹舵,盡管相似钮孵,但是擁有不同的性能和查詢特征,因為被分別存儲在不同的文檔中眼滤。(也就是不同的記錄row中)巴席。后面將介紹parent/child文檔。
2.3 索引的基礎(chǔ)
在ES中最大的獨立的數(shù)據(jù)單元是index
诅需。索引是文檔的邏輯和物理劃分(partition)漾唉。文檔和文檔類型對于index來說是唯一的。索引不知道包含在其他索引中的數(shù)據(jù)堰塌。從可操作角度看赵刑,需要性能和持久性(durability)相關(guān)的選項(option)被設(shè)置為per-index層面。
從查詢的角度场刑,當ES支持交叉索引搜索時般此,通常in practice it usually makes more organizational sense to design for searches against individual indexes.
ES索引是在一個獨立的運行時服務(wù)器實例一個完全劃分的universe。文檔和類型映射是以index范圍內(nèi)進行的。所以跨索引重用名稱和id是安全的铐懊。索引同樣擁有供集群復(fù)制邀桑,sharding,定制文本分析和其他考慮的本身的設(shè)置科乎。
ES的索引不是與Lucene索引一一對應(yīng)的壁畸。實際上,他們是一個Lucene索引的集合(通常設(shè)為5)對shard有一個備份喜喂。一個單一的機器可能相比較其他的機器對同一個索引有或多或少的shards瓤摧。ES盡可能地保持所有索引的全部數(shù)據(jù)在所有的機器上都一致,即使那意味著某些索引可能會在某臺機器上不成比例地出現(xiàn)玉吁。每個shard擁有一個可配置數(shù)目地全replica照弥,這總是存儲在唯一地實例上。如果cluster不足夠大來支撐指定數(shù)量地replica进副,cluster health會被報告為惡化的(‘yellow’)狀態(tài)这揣。基本的ES開發(fā)安裝因此在使用默認索引運行影斑。一個單一運行的實例沒有peer來復(fù)制其數(shù)據(jù)给赞。注意這對于開發(fā)過程沒有實際的影響。然后矫户,建議大家ES在產(chǎn)品環(huán)境中運行在多個服務(wù)器上片迅。正如一個clustered數(shù)據(jù)庫,數(shù)據(jù)的保證依賴于多個節(jié)點的可用上皆辽。
我們在下個section:Basic CRUD介紹基本使用index的操作命令
2.4 CRUD基礎(chǔ)
Let’s perform some basic operations on data. Elasticsearch is RESTish in design and tends to match HTTP verbs up to the Create, Read, Update, and Delete operations that are fundamental to most databases. We’ll create an index, then a type, and finally a document within that index using that type. Open up elastic-hammer, and we’ll issue the following operations from figure 2.3.
F 2.3 Simple CRUD
// Create a type called 'hacker'
PUT /planet/hacker/_mapping
{
"hacker": {
"properties": {
"handle": {"type": "string"},
"age": {"type": "long"}}}}
// Create a document
PUT /planet/hacker/1
{"handle": "jean-michel", "age": 18}
// Retrieve the document
GET /planet/hacker/1
// Update the document's age field
POST /planet/hacker/1/_update
{"doc": {"age": 19}}
// Delete the document
DELETE /planet/hacker/1
fig-simplecrud
// Create an index named 'planet'
PUT /planet
在上面的例子中柑蛇,我們可以看到ES全部的CRUD生命周期。現(xiàn)在我們可以對數(shù)據(jù)執(zhí)行一些基本的操作∏疲現(xiàn)在就到了最為關(guān)鍵的地方了——搜索耻台。注意URL模式與這些操作是一致的,大多數(shù)的URL形如/index/type/docid
空另,使用一個下劃線前綴作為特定操作的名字空間盆耽。
database ACID
- atomicity;
- consistency;
- isolation;
- durability:
* if a flight booking reports that a seat has successfully been booked, then the seat will remain booked even if the system crashes. In distributed transactions, all participating servers must coordinate before commit can be acknowledged. This is usually done by a two-phase commit protocol.
* Many DBMSs implement durability by writing transactions into a transaction log that can be reprocessed to recreate the system state right before any later failure. A transaction is deemed committed only after it is entered in the log.
shard
shard是Lucene的獨立的實例,這個工作單元是由elasticsearch自動管理的扼菠。一個index是一個邏輯的名字空間摄杂,其指向主從shards。但是我們不需要關(guān)注一個索引如何定義主從shard的數(shù)量循榆,不會直接接觸到shard匙姜,只需要直接處理index。ES將shards分發(fā)給cluster中所有的節(jié)點冯痢。,并且可以在node失敗時或者新增nodes時自動地將shards從一個node移向另外一個。
第三章 搜索數(shù)據(jù)
3.1 搜索API
搜索API通常使用/index
和index/type
后接_search
作為路徑浦楣。索引搜索可能是/myidx/_search袖肥,而對獨立文檔類型的范圍搜索可以是/myidx/mytype/_search
。搜索API的作用是調(diào)用一個查詢振劳,其參數(shù)可以是結(jié)果集合的最大數(shù)椎组,結(jié)果偏移位置,和一些性能指標選項历恐。搜索API同樣提供Faceting和過濾(Filtering)寸癌,這些在后面會介紹到。
下面展示了搜索API的骨架弱贼。例子中只有size和query參數(shù)被設(shè)置蒸苇,沒有facet或者filter被應(yīng)用。例子很簡單吮旅。_search
后綴可以使用GET
和POST
HTTP方法溪烤。
Simple Query
{
"size": 3,
"query": {
"match": {"hobbies": "skateboard"}
}}
Query DSL用來確定哪些文檔匹配了指定的限定。同樣對文檔進行排序庇勃,通過他們的相似度來做排序的基準檬嘀,這在Lucene中是標準的技術(shù)術(shù)語。相似度度值通常被稱文檔的打分(score)责嚷。The Query DSL is employed as the contents of either the query key in JSON posted to the _search endpoint as in the example above.
3.1.1 Mixing查詢鸳兽、過濾器和Facets
- http://www.slideshare.net/medcl/elastic-search-training1-brief-tutorial#btnLast
- http://www.slideshare.net/endless_yy/ss-27849480
transportclient, node client
3.2 分析
3.2.1 文本分析
分析自然是最為重要的和神奇的特性了,可以處理自然語言及復(fù)雜數(shù)據(jù)罕拂。
下面出現(xiàn)的問題揍异,就是當數(shù)據(jù)存儲在文檔中時,知道哪里和什么時候使用分析聂受,然后在每次查詢過來時蒿秦,根據(jù)那個字段的分析規(guī)則進行匹配。文檔進行分析過程如下:
- 文檔的更新和創(chuàng)建使用
PUT
或者POST
- 文檔中字段的值通過一個分析器后被轉(zhuǎn)化成零個蛋济、1個或者多個可索引的token
- 被token化的值存放在索引中個棍鳖,指向了這個文檔的全文
3.2.2 分析API
The easiest way to see analysis in action is with the Analyze API, which lets you test pieces of text against any analyzer. To test the words “candles” and “candle” for instance, against a snowball analyzer, you would issue the query in Figure 3.6.
使用分析API是看分析過程的最佳方法,你可以對分析器測試各種文檔輸入碗旅。例如測試詞“candles”和“candle”渡处,使用一個snowball分析器:
F 3.6 使用分析API
GET '/_analyze?analyzer=snowball&text=candles%20candle&pretty=true'
在這種情形下,我們可以分析“candles candle”來展示兩個相似的詞是如何被分析的祟辟。你會得到下面的結(jié)果:
F 3.7 Analysis API Output
{
"tokens" : [ {
"token" : "candl",
"start_offset" : 0,
"end_offset" : 7,
"type" : "<ALPHANUM>",
"position" : 1
}, {
"token" : "candl",
"start_offset" : 8,
"end_offset" : 14,
"type" : "<ALPHANUM>",
"position" : 2
} ]
}
分析API在試著區(qū)分為何一些詞完全一樣的token化還有其他沒有的時候是最有價值的医瘫。如果你被不知道如何解決沒有匹配的查詢難住,首先你可以使用分析API來試試一些文本
定制分析器
分析器是典型的三步走:
- Character Filtering: 將輸入字符串轉(zhuǎn)化為一個不同的字符串
- Tokenization: 將char過濾后的字符串轉(zhuǎn)化為一個token的數(shù)組
- Token Filtering: 將過濾過的token轉(zhuǎn)化為一個mutated token數(shù)組
3.3 基于相似度的排名
現(xiàn)在我們走入了ES的核心部分旧困。搜索是兩大步:
- 匹配所有滿足要求的文檔醇份。這是IR領(lǐng)域的布爾搜索稼锅,因為這步只是存在與否的的衡量。
- 第二步則是基于與查詢的相似度進行打分僚纷,然后以打分的倒序展示結(jié)果矩距。
有多個可配置的相似度算法。本章介紹默認的TFIDF相似度類怖竭。這是相當著名的打分算法锥债,在Lucene的TFIDFSimilarity
類中實現(xiàn)。
基本思想:
文檔的分數(shù)高當:
- 被匹配的term是“罕見的”痊臭,指這個term比其他term在更少的文檔中出現(xiàn)哮肚。
- term以一個很高的頻率出現(xiàn)在該文檔中
- 如果多個term在查詢中,該文檔比其他文檔包含更多的查詢term
- 字段field或文檔在索引時指定了boost因子或者查詢時間(query time)广匙。
上面的列表是極其簡化的相似度計算的思想允趟。請牢記的是,所有的打分因子之間關(guān)系不都是線性的艇潭,還有一些比較微妙的地方拼窥。然而,大多數(shù)時間蹋凝,Lucene已經(jīng)做了你想要做的鲁纠,而不要你自己計算TF/IDF。而且鳍寂,ES支持可配置的相似度算法改含,如BM25算法。如果給你的算法包對你作用不大迄汛,你自己可以寫一個script
查詢捍壤,這樣可以根據(jù)自己的想法對文檔進行打分,或者寫一個實現(xiàn)你自己的打分算法的java插件鞍爱。
一般來說鹃觉,TF/IDF、顯式的排序(如按日期降序)睹逃、和腳本查詢盗扇,將給你很好的效果。
分面
3.4.1 什么是分面(Faceting)
聚合統(tǒng)計是ES的一個核心部分沉填,可以通過Search API進行調(diào)用疗隶。分面(facet)總是跟一個查詢一起,讓我們返回正常查詢結(jié)果和聚合統(tǒng)計翼闹。想象一個用戶使用電影名來查詢電影斑鼻。使用分面搜索你可以給出結(jié)果中不同類屬的聚合數(shù)量。如果你曾經(jīng)在一個電商網(wǎng)站上進行過搜索猎荠,你可能會在sidebar處看到一個下拉選項坚弱。
分面是高度可定制的蜀备,同樣也是可以復(fù)合的。除了統(tǒng)計不同字段的值外史汗,分面可以使用更加復(fù)雜的群組特性琼掠,例如時間跨度、嵌套過濾器停撞、甚至全面、嵌套的elasticsearch查詢悼瓮。
Filtering
filter對搜索的執(zhí)行path有著明顯的影響戈毒。當查詢給出哪些文檔出現(xiàn)在結(jié)果中,以及他們?nèi)绾伪淮蚍趾岜ぃ^濾器只會給出哪些文檔出現(xiàn)在結(jié)果中埋市。這個可以獲得一個極其快速的查詢。另外命贴,一些限制可以通過過濾器指定道宅。過濾器可以將結(jié)果集進行切分,且不需要執(zhí)行代價昂貴的打分計算胸蛛。過濾器也可以用來污茵,當一個term必須要匹配但是其對文檔整體分數(shù)的影響應(yīng)該是一個確定的量而不管TF/IDF分值。最后葬项,不同與查詢的是泞当,filters可以被緩存,當filter被重復(fù)使用時民珍,導(dǎo)致了一個明顯的性能提升襟士。
elasticsearch有三種filter出現(xiàn)方式∪铝浚控制filter應(yīng)用在query和factes上陋桂,查詢或者自查詢,或者facet蝶溶。下面列表說明
- Queries of the filtered/constant_score類型:這些都內(nèi)嵌在query字段中嗜历,filters將影響查詢結(jié)果和facet計數(shù)。
- top-level filter element: 確定一個filter在搜索的根身坐,只會過濾查詢秸脱,但不會影響facet
- facets with facet_filter選項:給每個facet添加可選的facet_filter元素,這個可以用來在數(shù)據(jù)被聚合之前預(yù)先過濾數(shù)據(jù)部蛇。這個過濾器將只會影響定義在其里面的facet摊唇,不會影響查詢結(jié)果。
3.5.1 過濾的三種不同過程
使用filtered和constant_score_quries
這兩種類型均允許嵌套一個regular查詢涯鲁。過濾器先運行巷查,然后查詢和任何的的facets有序,如果filter足夠強地限制了結(jié)果集合,這將千載地提供了一個有效的安全的速度提升岛请。
// Load Dataset: products.eloader
POST /products/_search
{
"facets": {"department": {"terms": {"field": "department_name"}}},
"query": {
"filtered": {
"query": {"match": {"name": "fake"}},
"filter": {"term": {"department_name": "Books"}}}}}