最近項目有個需求,很棘手。有個統計功能,須要作到實時出結果。這個功能通過好幾我的的處理都沒有解決客戶的問題。到了我這裏,我就來填坑了。苦逼的程序猿,苦逼的命。誰叫我是這個項目現任負責人。經一番折騰大體瞭解到客戶對這個統計分析的需求以後,就進入技術選項。老套路,確定先百度、谷歌、大神羣各類諮詢、瞭解。最後決定使用elasticseaarch。至於爲什麼選擇它,相關同窗本身百度去。而我選擇的緣由就是簡單、易於維護、成本低、性能也是gan gan 的。html
接下來咱們看看elasticsearch index api是如何使用java 來進行相關操做。強烈建議在閱讀如下所說的內容前必須先對elasticsearch有必定的瞭解java
參考官網APIgit
low level [https://www.elastic.co/guide/...]()
high level [https://www.elastic.co/guide/...]()github
如下源碼下載鏈接:ESRestClient.java http://download.csdn.net/down...算法
pom.xmlapi
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>5.6.4</version>
</dependency>數組
建立鏈接app
private static Logger log = LoggerFactory.getLogger(ESRestClient.class);
private static RestClient lowLevelRestClient = null;
private static RestHighLevelClient highLevelRestClient = null;elasticsearch
/** * @Description: 初始化 * @return void * @throws * @author JornTang * @date 2017年12月23日 */ public void init(){ RestClientBuilder builder = RestClient.builder(new HttpHost("127.0.0.1", 9200)); builder.setRequestConfigCallback(new RestClientBuilder.RequestConfigCallback() { @Override public RequestConfig.Builder customizeRequestConfig(RequestConfig.Builder requestConfigBuilder) { requestConfigBuilder.setConnectTimeout(10000); requestConfigBuilder.setSocketTimeout(30000); requestConfigBuilder.setConnectionRequestTimeout(10000); return requestConfigBuilder; } }); builder.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() { @Override public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) { return httpClientBuilder.setDefaultIOReactorConfig( IOReactorConfig.custom() .setIoThreadCount(100)//線程數配置 .setConnectTimeout(10000) .setSoTimeout(10000) .build()); } }); //設置超時 builder.setMaxRetryTimeoutMillis(10000); //構建low level client lowLevelRestClient = builder.build(); //構建high level client highLevelRestClient = new RestHighLevelClient(lowLevelRestClient); log.info("ESRestClient 初始化完成。。。。。。。。。"); }
經過init方法構造RestClient 、RestHighLevelClientide
那麼如何操做index
單條處理
/** * @Description: low level put index * @throws IOException * @return void * @throws * @author JornTang * @date 2017年12月22日 */ public static void lowLevelPutIndex(String idnex, String type, ArchiveMapperVo mapperVo) throws IOException{ Map<String, String> params = Collections.emptyMap(); ArchiveMapper mapper = new ArchiveMapper(); BeanUtils.copyProperties(mapperVo, mapper); HttpEntity entity = new NStringEntity(JSON.toJSONString(mapper), ContentType.APPLICATION_JSON); Response response = lowLevelRestClient.performRequest("PUT", "/"+idnex+"/"+type+"/" + mapperVo.getDocumentId(), params, entity); StatusLine statusLine = response.getStatusLine(); log.info("索引執行put:【" + statusLine.getStatusCode() + "】" + statusLine.toString()); } /** * @Description: low level delete index * @throws IOException * @return void * @throws * @author JornTang * @date 2017年12月22日 */ public static void lowLevelDeleteIndex(String idnex, String type, String documentId) throws IOException{ Map<String, String> params = Collections.emptyMap(); Response response = lowLevelRestClient.performRequest("DELETE", "/"+idnex+"/"+type+"/" + documentId, params); StatusLine statusLine = response.getStatusLine(); log.info("索引執行delete:【" + statusLine.getStatusCode() + "】" + statusLine.toString()); }
批量處理
/**
*/
public static void bulkPutIndex(String idnex, String type, List<ArchiveMapper> mappers) throws Exception{
BulkRequest request = new BulkRequest();
if(mappers== null || mappers.size()< 1){
throw new ESIndexException("mappers can not be empty");
}
for (int i = 0; i < mappers.size(); i++) {
ArchiveMapper mapper = mappers.get(i);
request.add(new IndexRequest(idnex, type, mapper.getId())
.opType("create")
.source(JSON.toJSONString(mapper),XContentType.JSON));
}
BulkResponse bulkResponse = highLevelRestClient.bulk(request);
RestStatus stat = doSuccessful(bulkResponse);
//log.info("索引執行bulk put:【" + stat.getStatus() + "】" + stat.toString());
}
是否是以爲很是簡單呢?上面的代碼不能直接使用要結合本身的實際狀況。
好比:數據建模、model定義
數據建模參考:
PUT archives { "mappings": { "archive": { "_all": { "enabled": false }, "properties": { "id": { "type": "keyword" }, "arch_type": { "type": "integer" }, "archive_id":{ "type":"integer" }, "room_id":{ "type":"integer" }, "if_store":{ "type":"integer" }, "handover_state":{ "type":"integer" }, "crt_date":{ "type":"long" }, "if_hasfile":{ "type":"integer" }, 「doc_date」:{ "type":"long" }, "doc_year":{ "type":"integer" }, "fond_code":{ "type":"keyword" }, "cate_code":{ "type":"keyword" }, "keep_time":{ "type":"integer" }, "file_click":{ "type":"integer" }, "storage_date":{ "type":"long" }, "storage_year":{ "type":"integer" }, "into_archive_date":{ "type":"long" }, "into_archive_year":{ "type":"integer" }, "vol_in_num":{ "type":"integer" }, "pro_vol":{ "type":"integer" }, "pro_doc":{ "type":"integer" }, "file_num":{ "type":"integer" }, "file_size":{ "type":"long" }, "page_nmbr":{ "type":"integer" } } } }, "settings": { "number_of_shards":3, "number_of_replicas":0 } }
屬性類型定義參考:
經常使用的數據類型
Ø Boolean 布爾類型
布爾字段接受JSON true和false值,但也能夠接受被解釋爲true或false的字符串
示例以下:
PUT my_index { "mappings": { "my_type": { "properties": { "is_published": { "type": "boolean" } } } } } POST my_index/my_type/1 { "is_published": "true" } GET my_index/_search { "query": { "term": { "is_published": true } } }
如下參數被boolean字段接受:
boost
映射字段級查詢時間提高。接受一個浮點數,默認爲1.0。
doc_values
該字段是否應該以列步方式存儲在磁盤上,以便稍後用於排序,聚合或腳本?接受true (默認)或false。
index
該領域應該搜索?接受true(默認)和false。
null_value
接受上面列出的任何真值或假值。該值被替換爲任何顯式null值。默認爲null,這意味着該字段被視爲丟失。
store
字段值是否應該與_source字段分開存儲和檢索。接受true或false (默認)。
Ø Date 日期類型
JSON沒有日期數據類型,因此Elasticsearch中的日期能夠是:
· 包含格式的日期,如字符串"2015-01-01"或"2015/01/01 12:10:30"。
· 一個表明毫秒數的長數字。
· 自始至終秒的整數
在內部,日期轉換爲UTC(若是指定時區)並存儲爲表示毫秒之後的長數字。
日期格式能夠自定義,但若是沒有format指定,則使用默認值:
"strict_date_optional_time || epoch_millis"
示例以下:
PUT my_index { "mappings": { "my_type": { "properties": { "date": { "type": "date" } } } } } PUT my_index/my_type/1 { "date": "2015-01-01" } PUT my_index/my_type/2 { "date": "2015-01-01T12:10:30Z" } PUT my_index/my_type/3 { "date": 1420070400001 } GET my_index/_search { "sort": { "date": "asc"} }
定義多個日期格式
多個格式能夠經過分隔||做爲分隔符來指定。每一個格式將依次嘗試,直到找到匹配的格式。第一種格式將被用於將毫秒自時代的值轉換回字符串
PUT my_index { "mappings":{ "my_type":{ "properties":{ "date":{ "type":"date", "format":"yyyy-MM-dd HH:mm:ss || yyyy- MM-dd || epoch_millis" } } } } }
如下參數被date字段接受:
boost
映射字段級查詢時間提高。接受一個浮點數,默認爲1.0。
doc_values
該字段是否應該以列步方式存儲在磁盤上,以便稍後用於排序,聚合或腳本?接受true (默認)或false。
format
能夠解析的日期格式。默認爲 strict_date_optional_time||epoch_millis。
locale
自從月份以來,解析日期時使用的語言環境在全部語言中都沒有相同的名稱和/或縮寫。默認是 ROOT語言環境,
ignore_malformed
若是true,格式不正確的號碼被忽略。若是false(默認),格式不正確的數字會拋出異常並拒絕整個文檔。
index
該領域應該搜索?接受true(默認)和false。
null_value
接受其中一個配置的日期值format做爲代替任何顯式null值的字段。默認爲null,這意味着該字段被視爲丟失。
store
字段值是否應該與_source字段分開存儲和檢索。接受true或false (默認)。
Ø Keyword 關鍵字類型
用於索引結構化內容的字段,如電子郵件地址,主機名,狀態碼,郵政編碼或標籤。
它們一般用於過濾(找到個人全部博客文章,其中 status爲published),排序,和聚合。關鍵字字段只能按其確切值進行搜索。
若是您須要索引全文內容(如電子郵件正文或產品說明),則可能須要使用text字段。
示例以下:
PUT my_index { "mappings": { "my_type": { "properties": { "tags": { "type": "keyword" } } } } }
如下參數被keyword字段接受:
boost
映射字段級查詢時間提高。接受一個浮點數,默認爲1.0。
doc_values
該字段是否應該以列步方式存儲在磁盤上,以便稍後用於排序,聚合或腳本?接受true (默認)或false。
eager_global_ordinals
全球序言是否應該在刷新的時候急切地加載?接受true或false (默認)。對於常常用於術語聚合的字段,啓用此功能是一個不錯的主意。
fields
多字段容許爲了避免同的目的以多種方式對相同的字符串值進行索引,例如用於搜索的字段和用於排序和聚合的多字段。
ignore_above
不要索引任何比這個值長的字符串。默認爲 2147483647全部值都將被接受。
index
該領域應該搜索?接受true(默認)或false。
index_options
爲了評分目的,應該在索引中存儲哪些信息。默認爲,docs但也能夠設置爲freqs在計算分數時考慮術語頻率。
norms
評分查詢時是否應考慮字段長度。接受true或false(默認)。
null_value
接受一個替代任何顯式null 值的字符串值。默認爲null,這意味着該字段被視爲丟失。
store
字段值是否應該與_source字段分開存儲和檢索。接受true或false (默認)。
similarity
應使用 哪一種評分算法或類似性。默認爲BM25。
normalizer
如何在索引以前預先處理關鍵字。默認爲null,意味着關鍵字保持原樣。
Ø Number 數字類型
如下數字類型受支持:
long
一個帶符號的64位整數,其最小值爲-263,最大值爲。 263-1
integer
一個帶符號的32位整數,其最小值爲-231,最大值爲。 231-1
short
一個帶符號的16位整數,其最小值爲-32,768,最大值爲32,767。
byte
一個有符號的8位整數,其最小值爲-128,最大值爲127。
double
雙精度64位IEEE 754浮點。
float
單精度32位IEEE 754浮點。
half_float
一個半精度的16位IEEE 754浮點。
scaled_float
一個由long一個固定比例因子支持的浮點。
示例以下:
PUT my_index { "mappings": { "my_type": { "properties": { "number_of_bytes": { "type": "integer" }, "time_in_seconds": { "type": "float" }, "price": { "type": "scaled_float", "scaling_factor": 100 } } } } }
對於double,float和half_float類型須要考慮-0.0和 +0.0不一樣的值存儲。作一個term查詢 -0.0將不匹配+0.0,反之亦然。一樣適用於範圍查詢真:若是上限是-0.0那麼+0.0將不匹配,若是下界+0.0那麼-0.0將不匹配
那麼咱們應該如何使用數字類型。應遵循如下規則
l 至於整數類型(byte,short,integer和long)而言,你應該選擇這是足以讓你的用例最小的類型。這將有助於索引和搜索更高效。但請注意,考慮到根據存儲的實際值對存儲進行優化,選擇一種類型將不會影響存儲要求
l 對於浮點類型,使用縮放因子將浮點數據存儲到整數中一般會更高效,這正是scaled_float 類型所作的。例如,一個price字段能夠存儲在一個 scaled_floatwith scaling_factor中100。全部的API均可以工做,就好像字段被存儲爲double同樣,可是在elasticsearch下面,將會使用分數price*100,這是一個整數。這對於節省磁盤空間很是有幫助,由於整數比浮點更容易壓縮。scaled_float交易磁盤空間的準確性也很好用。例如,想象一下,您正在跟蹤CPU利用率,並將其做爲介於0和之間的數字1。它一般沒有多大的CPU使用率是12.7%或13%,因此你可使用一個scaled_float 帶有scaling_factor的100,以節省空間,以全面cpu利用率到最近的百分比
若是scaled_float是不適合,那麼你應該選擇一個適合的浮點類型中的用例是足夠最小的類型:double,float和half_float。這裏是一個比較這些類型的表格,以幫助作出決定
類型
最小值
最大值
重要的位/數字
double
2-1074
(2-2-52)·21023
53 / 15.95
float
2-149
(2-2-23)·2127
24 / 7.22
half_float
2-24
65504
11 / 3.31
如下參數被數字類型接受:
coerce
嘗試將字符串轉換爲數字並截斷整數的分數。接受true(默認)和false。
boost
映射字段級查詢時間提高。接受一個浮點數,默認爲1.0。
doc_values
該字段是否應該以列步方式存儲在磁盤上,以便稍後用於排序,聚合或腳本?接受true (默認)或false。
ignore_malformed
若是true,格式不正確的號碼被忽略。若是false(默認),格式不正確的數字會拋出異常並拒絕整個文檔。
index
該領域應該搜索?接受true(默認)和false。
null_value
接受與type替換任何顯式null值的字段相同的數字值。默認爲null,這意味着該字段被視爲丟失。
store
字段值是否應該與_source字段分開存儲和檢索。接受true或false (默認)。
注:參數scaled_float
scaled_float 接受一個額外的參數:
scaling_factor
編碼值時使用的縮放因子。在索引時間,數值將乘以該因子,並四捨五入到最接近的長整數值。例如,scaled_float用scaling_factor的10將內部存儲2.34的23全部搜索時操做(查詢,彙總,排序)的行爲就好像該文件是一個值2.3。scaling_factor提升精確度的值較高,但也增長了空間要求。該參數是必需的。
Ø Text 文本數據類型
用於索引全文值的字段,例如電子郵件的正文或產品的說明。這些字段是analyzed,即它們經過 分析器來轉換字符串成索引以前的單個條目列表。分析過程容許Elasticsearch 在 每一個全文字段中搜索單個單詞。文本字段不用於排序,也不多用於聚合(儘管 重要的文本聚合 是一個明顯的例外)。
若是您須要爲電子郵件地址,主機名,狀態碼或標籤等結構化內容編制索引,則可能須要使用keyword字段。
示例以下:
PUT my_index { "mappings": { "my_type": { "properties": { "full_name": { "type": "text" } } } } }
有時同一字段的全文本(text)和關鍵字(keyword)版本都是有用的:一個用於全文搜索,另外一個用於聚合和排序。這能夠經過多領域來實現 。
如下參數被text字段接受:
analyzer
的分析器,其應該被用於 analyzed既在索引時間和搜索時間(除非被重寫字符串字段 search_analyzer)。默認爲默認的索引分析器或 standard分析器。
boost
映射字段級查詢時間提高。接受一個浮點數,默認爲1.0。
eager_global_ordinals
全球序言是否應該在刷新的時候急切地加載?接受true或false (默認)。在常常用於(重要)術語聚合的字段上啓用此功能是一個好主意。
fielddata
該字段可使用內存中的字段數據進行排序,聚合或腳本嗎?接受true或false(默認)。
fielddata_frequency_filter
專家設置容許決定fielddata 啓用時在內存中加載哪些值。默認狀況下全部的值都被加載。
fields
多字段容許爲了避免同的目的以多種方式對相同的字符串值進行索引,例如一個字段用於搜索,一個多字段用於排序和聚合,或者由不一樣的分析器分析相同的字符串值。
index
該領域應該搜索?接受true(默認)或false。
index_options
索引中應該存儲哪些信息,用於搜索和突出顯示目的。默認爲positions。
norms
評分查詢時是否應考慮字段長度。接受true(默認)或false。
position_increment_gap
應該插入到一個字符串數組的每一個元素之間的假詞位置的數量。默認爲position_increment_gap 默認分析儀上的配置100。100被選中是由於它能夠經過字段值匹配術語來防止具備至關大的短語(小於100)的短語查詢。
store
字段值是否應該與_source字段分開存儲和檢索。接受true或false (默認)。
search_analyzer
本analyzer應該在搜索時使用 analyzed的字段。默認爲analyzer設置。
search_quote_analyzer
本analyzer應在搜索時遇到一個短語時使用。默認爲search_analyzer設置。
similarity
應使用 哪一種評分算法或類似性。默認爲BM25。
term_vector
術語向量是否應該存儲在一個analyzed 字段中。默認爲no。
Ø Feilds 多領域參數使用
爲了避免同的目的,以不一樣的方式對相同的字段進行索引一般是有用的。這是多領域的目的。例如,一個string 字段能夠映射爲text全文搜索的字段,也能夠映射keyword爲排序或聚合的字段:
示例以下:
PUT my_index { "mappings": { "my_type": { "properties": { "city": { "type": "text", "fields": { "raw": { "type": "keyword" } } } } } } }
PUT my_index/my_type/1 { "city": "New York" } PUT my_index/my_type/2 { "city": "York" } GET my_index/_search { "query": { "match": { "city": "york" } }, "sort": { "city.raw": "asc" }, "aggs": { "Cities": { "terms": { "field": "city.raw" } } } }
該city.raw字段是該字段的一個keyword版本city。
該city字段可用於全文搜索。
該city.raw字段可用於排序和聚合
使用多個分析器進行多字段編輯
另外一個多字段的用例是以不一樣的方式分析相同的字段以得到更好的相關性。例如,咱們能夠用standard分析器對字段進行索引,該 分析器將文本分解成文字,再用english分析器 將文字分解爲詞根:
PUT my_index { "mappings": { "my_type": { "properties": { "text": { "type": "text", "fields": { "english": { "type": "text", "analyzer": "english" } } } } } } } PUT my_index/my_type/1 { "text": "quick brown fox" } PUT my_index/my_type/2 { "text": "quick brown foxes" } GET my_index/_search { "query": { "multi_match": { "query": "quick brown foxes", "fields": [ "text", "text.english" ], "type": "most_fields" } } }
該text字段使用的standard分析儀。
該text.english字段使用的english分析儀。
索引兩個文件,一個與fox另外一個foxes。
查詢text和text.english字段並結合分數。
該text字段包含fox第一個文檔和foxes第二個文檔中的術語。該text.english字段包含fox這兩個文檔,由於foxes被阻止fox。
查詢字符串也由standard分析器分析該text 字段,並由english分析器分析text.english字段。詞幹字段容許查詢foxes也匹配包含正義的文檔fox。這使咱們能儘量多地匹配文檔。經過查詢未定text域,咱們提升了foxes準確匹配的文檔的相關性得分。
Ø 元數據字段
_all 字段:一個把其它字段值((("metadata, document", "_all field")))((("_all field", sortas="all field")))看成一個大字符串來索引的特殊字段。query_string
查詢子句(搜索?q=john
)在沒有指定字段時默認使用_all
字段
禁用示例
PUT /my_index/_mapping/my_type
{
"my_type": {
"_all": { "enabled": false }
}
}
若是_all字段被禁用,則URI搜索請求與 query_string和simple_query_string查詢將沒法用它來查詢,可是你能夠設置一個指定字段。以下示例
PUT my_index
{
"mappings": {
"my_type": {
//禁用_all字段
"_all": {
"enabled": false
},
"properties": {
"content": {
"type": "text"
}
}
}
},
"settings": {
//設置query_string 查詢指定的字段
"index.query.default_field": "content"
}
}
_source字段:該_source字段包含在索引時間傳遞的原始JSON文檔正文。這個 _source字段自己沒有索引(所以是不可搜索的),可是它被存儲以便在執行獲取請求(好比get或者search)的時候返回 。
_source段會在索引內產生存儲開銷。出於這個緣由,它能夠被禁用。以下:
PUT my_index { "mappings":{ "my_type":{ " _ source":{ "enabled":false } } } }
若是_source字段被禁用,如下功能將不在被支持
· update,update_by_query和reindexAPI。
· 高亮顯示
· 將索引從一個Elasticsearch索引從新索引到另外一個索引的能力,能夠更改映射或分析,也能夠將索引升級到新的主要版本。
· 經過查看索引時使用的原始文檔來調試查詢或聚合的能力。
· 在未來有可能自動修復索引損壞。
若是磁盤空間是一個問題,而是增長 壓縮級別而不是禁用_source。
在Elasticsearch中,對文檔的個別字段設置存儲的作法一般不是最優的。整個文檔已經被存儲爲_source
字段。使用_source
參數提取你須要的字段老是更好的。
這個時候你可能會不想保存全部字段信息,那麼你講能夠經過如下方式指定你要存儲的字段。以下
PUT my_index { "mappings": { "my_type": { "_source": { //包含,支持通配符定義 "includes": [ "*.count", "meta.*" ], //不包含,支持通配符定義 "excludes": [ "meta.description", "meta.other.*" ] } } } } PUT my_index/my_type/1 { "requests": { "count": 10, "foo": "bar" }, "meta": { "name": "Some metric", "description": "Some metric description", "other": { "foo": "one", "baz": "two" } } }
注:以上方式只是過濾存儲的字段,但每一個字段依舊能夠被搜索
寫在最後,針對具體相關api請參考elasticsearch官網。
建議:在實際項目中請結合線程池能夠在建立索引時大大的提高性能
【其餘連接】檔案管理系統
本篇文章由一文多發平臺ArtiPub自動發佈