Elasticsearch

Elasticsearch

為什么要有搜索引擎?

????? 在傳統(tǒng)的數據庫中,如果想實現搜索一般我們會用like方式,但遇到不是完全匹配或有差異的的就搜索不到了。

????? 而且傳統(tǒng)的數據庫實現搜索不靠譜,性能差、效率低。


什么是Elasticsearch?

????? Elasticsearch是一個基于Lucene的搜索服務器,他提供了一個分布式多用戶能力的全文搜索引擎,基于RESTful Web接口。

????? Elasticsearch是用Java開發(fā)的,隱藏了復雜性,開箱即用,并設計用于云計算,能夠達到實時搜索,穩(wěn)定、可靠、快速、安裝方便(插件可不方便),不僅能對海量規(guī)模的數據完成分布式索引和檢索,還能提供數據聚合分析。

????? Lucene就是一個jar包里面有著大量各種建立倒排索引,以及進行搜索的代碼、算法等。



什么是全文檢索?

????? 全文檢索是指計算機索引程序通過掃描文章中的每一個詞,對每一個詞建立一個索引,指明該詞在文章中出現的次數和位置,當用戶查詢時,檢索程序就根據事先建立好的索引進行查找,并將查詢結果反饋給用戶的檢索方式,這個過程類似于通過字段中的檢索字表查字的過程。

????? 也就是對全文數據進行詞、字、段落等更深層次的編輯、加工,將非結構化的數據一部分信息提取出來,重新組裝使得其有一定的結構,然后對此結構的數據進行搜索。



什么是倒排索引?

????? 根據分詞器對全文數據進行分詞,對分完后的詞進行標識,這個詞在哪里出現過,出現了幾次,再次查找的時候就根據位置去獲取完整的數據。



倒排索引包括:文檔的列表、數量,及詞條在每個文檔中出現的次數,出現的位置,每個文檔的長度,所有文檔的平均長度。



分詞器

????? 分詞器就是從一段文本切分出一個一個的詞條,并對詞條進行標準化處理。


分詞步驟

?????????? 預處理:過濾掉HTML標簽,特殊符號轉換等

?????????? 分詞:按照分詞器的算法進行分詞

?????????? 標準化:對分詞后的詞進行統(tǒng)一歸檔處理


Elasticsearch內置分詞器

????? Standard分詞器(默認):會將詞匯單元轉換為小寫形式,并去掉停用詞和標點符號,支持中文采用的方式為單字切分。

????? Simple分詞器:首先會通過非字母字符來分割文本信息,然后將詞匯單元統(tǒng)一為小寫形式,該分詞器會去掉數字類型的字符。

????? Whitespace分詞器:只是去除空格,對字符沒有l(wèi)owcase化,不支持中文,并不對生成的詞匯單元進行其他的標準化處理。

????? Language分詞器:特定語言的分詞器,不支持中文。

????? IK分詞器(不是內置的分詞器):對中文切分較好,通常會使用這個。



特點

????? 1.大型分布式集群(數百臺機器),處理PB級的數據

????? 2.開箱即用,非常簡單,操作也不復雜

????? 3.數據庫的功能面對很多領域是不夠用的(事務、聯(lián)機事務型操作、特殊的功能、全文檢索、同義詞處理、相關度排名、海量數據近實時處理等),Elasticsearch作為數據庫的一個補充,提供了數據庫所不能提供的很多功能。

???? Elasticsearch的麻煩在于插件,Elasticsearch的部分插件跟不上Elasticsearch的版本。

????? 4.近實時,從寫入數據到數據可以被搜索到有一個延遲(大約1秒)。基于Elasticsearch執(zhí)行搜索和分析可以達到秒級。



Elasticsearch核心概念

????? Cluster(集群):集群包含多個節(jié)點,每個節(jié)點屬于哪個集群是通過一個配置(集群名稱,默認是elasticsearch)來決定,只要配置文件內的集群名稱一致,內部會自動的去尋找,會自動組成集群。


????? Node(節(jié)點):集群中的單個節(jié)點,節(jié)點也有默認名稱(默認是隨機分配的),默認節(jié)點會加入一個名為elasticsearch的集群,如果直接啟動一堆節(jié)點,他們會自動組成一個elasticsearch集群,一個節(jié)點也可以組成集群。



數據庫ElasticsearchElasticsearch描述

database(庫)index (索引)一個索引通常代表一類數據

table(表)type(類型)Elasticsearch在index中建立type,通過mapping進行映射

column (列)field(字段)?

row(行)document(文檔)Elasticsearch存儲是文檔形的,相當于數據庫的行

constraint(約束)mapping(映射)創(chuàng)建index時,可以預先定義好字段的類型和相關屬性,這樣就可以自動進行類型轉換,如:字符串轉日期

SQL(數據操作語句)Query DSL(數據操作語句)GET/PUT/POST/DELETE

對應數據庫

select/update/delete

index(索引)indexed(索引)Elasticsearc默認是加上索引,觸發(fā)特殊指定不建立索引


架構



Gateway層:是Elasticsearch用來存儲索引文件的一個文件系統(tǒng),主要用來對數據進行長持久化以及整個集群重啟后可以通過Gateway重新恢復數據,且支持很多類型,例如:本地磁盤、共享存儲、hadoop的hdfs分布式存儲、亞馬遜的S3。


????? Dstributed Lucene DirectoryGateway上層就是Lucene的分布式框架,Lucene是做檢索的,但是他是一個單機的搜索引擎,像Elasticsearch這種分布式搜索引擎系統(tǒng),雖然底層使用Lucene,但是需要再每個節(jié)點上都運行Lucene進行相應的索引、查詢、以及更新等操作,就需要做成一個分布式的運行框架來滿足需求。

????? DstributedLucene Directory以上的是ES一些模塊。


????? Index Module索引模塊,對數據建立索引,也就是倒排索引。


????? Search Module搜索模塊,對數據進行查詢搜索。


????? Mapping數據映射與解析模塊,就是數據的每個字段可以根據建立的表結構進行映射、解析,如果沒有建立表結構,Elasticsearch會根據數據類型推測出數據結構后,自己生成一個Mapping,然后根據這個Mapping去解析數據。


????? River此模塊在Elasticsearch-2.0應該是被取消了,就是可以通過一些自定義的腳本將傳統(tǒng)的數據庫等數據源通過格式化轉換后同步到Elasticsearch集群。


????? DiscoveryElasticsearch是一個額集群有很多節(jié)點,很多節(jié)點需要互相發(fā)現對方,然后組成一個集群,包括選舉主節(jié)點,這些Elasticsearch都是用Discovery模塊,默認是使用Zen,也可以是使用EC2。


????? ScriptElasticsearch查詢還可以支持多種基本語言,包括mvel、js、python等。


????? Transport協(xié)議層,支持的也比較多,Thrift、Memcached、Http等,默認是Http。


????? JMXjava的一個遠程監(jiān)控管理框架,Elasticsearch是使用java實現的。


????? RESTful接口層,官方推薦使用RESTful接口,直接發(fā)送http情況,方便后續(xù)的nginx做代理、分發(fā),包括權限的管理是,通過http就很方便做了,如果使用java客戶端是直接調用Api,在做負載均衡及權限管理還是不太好做。



內部架構解析

Master節(jié)點

????? 主要職責是和集群操作相關的內容,如創(chuàng)建或刪除索引,跟跟蹤哪些節(jié)點是集群的衣服,決定哪些分片分配給相關的節(jié)點,穩(wěn)定的主節(jié)點對集群的監(jiān)控非常重要。


節(jié)點對等

????? 每個節(jié)點都能接收請求

????? 每個節(jié)點接收到請求后都能把該請求路由到有相關的數據的其他節(jié)點上。

????? 接收原始請求的節(jié)點負責采集數據并返回給客戶端


文檔數據路由原理

????? 1.文檔路由到分片上,一個索引由多個分片構成,當增刪改一個文檔時,Elasticsearch就需要決定存儲在哪個分片上。

????? 2.路由算法:shard=hash(routing) %number_of_pirmary_shards

???????????????? 1.每次增刪改查的時候,都有一個路由值,默認是文檔的_id值

???????????????? 2.對這個路由值使用哈希函數進行計算

???????????????? 3.計算出的值在和分片個數取余數,這個時候就確定了在哪個分片。

????? 3.算法決定了,主分片個數一旦確定就不能修改了。


分片和副本機制

1.index包含多個分片。

????? 2.每個分片都是一個最小的工作單元,承載部分數據,每個分片都是一個lucene實例,有完整的建立索引和處理請求的能力。

????? 3.增刪節(jié)點時,分片會自動的在集群中負載均衡

????? 4.主分片和副分片,每個document肯定只存在于某一個主分片及其對應的副分片,不可能存在于多個主分片中。

????? 5.副分片是主分片的副本,負責容錯,以及承擔讀請求負載

????? 6.主分片的數量在創(chuàng)建索引的時候就固定了,副分片的數量可以隨時修改。

????? 7.主分片的默認數量是5,副分片默認是1,默認有10個分片,5個主分片,5個副分片。

????? 8.主分片不能和自己的副分片在同一個節(jié)點(節(jié)點掛了,主和副都掛了,沒有意義,做不到容錯),但是可以和其他的主分片的副分片放在同一節(jié)點上。



水平擴容的過程

1.擴容后主分片和副分片都會自動負載均衡

????? 2.擴容后每個節(jié)點上的分片會減少,那么分配給每個分片的CPU、內存、IO資源會更多,性能會提高。

????? 3.擴容極限,如果有6個分片,擴容的極限就是6個節(jié)點,每個節(jié)點上一個分片,如果超出擴容極限,比如擴容到9個節(jié)點,那么可以增加副分片的個數。


Elasticsearch容錯機制

????? 如果master掛了,此時不是所有的主分片都是Active狀態(tài),所以此時的集群狀態(tài)是red。

????? 第一步:選舉出一臺服務器作為master

????? 第二步:新選舉出的master會把掛掉的主分片的某個副分片提升為主分片,此時集群的狀態(tài)是yellow,因為少了一個副分片,并不是所有的副分片都是Active狀態(tài)

????? 第三步:重啟故障機器,新的master會把所有的副本都復制一份到該節(jié)點上(同步一下掛了后發(fā)生的修改),此時集群的狀態(tài)為green,因為所有的主分片和副分片都是Active狀態(tài)。


刪除文檔

????? 標記為deleted,隨著數據量的增加,Elasticsearch會選擇合適的時間刪除。


文檔增刪改原理

????? 1.發(fā)送增刪改請求,可以選擇任意一個節(jié)點,該節(jié)點就成為協(xié)調節(jié)點。

????? 2.協(xié)調節(jié)點使用路由算法進行路由,然后將請求轉給主分片所在的節(jié)點,該節(jié)點處理請求,并把數據同步到它的副分片。

????? 3.協(xié)調節(jié)點對客戶端返回結果。


文檔查詢內部原理

????? 1.查詢請求發(fā)送任意一個節(jié)點,該節(jié)點就成了協(xié)調節(jié)點,該節(jié)點使用路由算法,算出文檔所在的主分片。

????? 2.協(xié)調節(jié)點把請求轉發(fā)給主分片,也可以轉發(fā)給副分片(使用輪詢調度算法,把請求平均的分配給主分片和副分片)。

????? 3.處理請求的節(jié)點是把結果返回給協(xié)調節(jié)點,協(xié)調節(jié)點在返回給應用程序。


特殊情況:請求的文檔還在建立索引的過程中,主分片上存在,但副分片上不存在,但請求被轉發(fā)到了副分片上,這時就提示找不到文檔了。


索引為什么不可變?

????? 不需要鎖,提升了并發(fā)的性能

????? 可以一直在緩存中

????? 節(jié)省了CPU和IO開銷


版本控制 & 鎖 & 數據一致性

????? Elasticsearch采用樂觀鎖來保證數據的一致性,也就是說,當用戶對document進行操作時,并不需要對該document做加鎖和解鎖的操作,只需要制定要操作的版本即可,當版本號一致時,Elasticsearch會允許該操作順利執(zhí)行,而當版本號存在沖突時,Elasticsearch會拋出異常提示沖突了。()

????? Elasticsearch的版本號取值范圍是1到2^63-1

????? 內部版本控制:使用_version

????? 外部版本控制:Elasticsearch在處理外部版本號時會與內部版本號處理有些不同,他不再是檢查version是否和請求中的指定數值相同,而是檢查當前的version是否比指定數值小,如果請求成功,那么外部版本號就會被存儲到文檔的_verison中。

????? 為了保證_version和外部版本控制的數據一致性使用version_type=external



數據類型

字符型text長文本,在建立索引前會將這些文本進行分詞,轉化成分詞組合,建立索引,text類型不能排序和聚合。

keyword不需要進行分詞,可以用來檢索過濾、排序和聚合。

只能用本身進行檢索

數值類型long?

integer?

short?

byte?

double?

float?

日期類型date?

布爾類型boolean?

二進制類型binary?

數組類型Array字符型數組:

[ "one", "two" ]

整型數組:[ 1, 2 ]

數組型數組:[ 1, [ 2, 3 ]] 等價于[ 1, 2, 3 ]

對象數組:[ { "name":? "Mary", "age": 12 }, { "name":? "John", "age": 10 }]

對象類型_ object _用于單個json對象

嵌套類型_ nested _用于json數組

???

地理坐標類型geo-point經度

geo-shape類似多邊形的復雜形狀

Ipv4_ ip _用于表示Ipv4地址

Completion類型_ completion _提供自動補全建議

Toekn count類型_ token_count _用于統(tǒng)計做了標記的字段的index數目,該值會一直增加,不會因為過濾條件而減少

Mapper-murmur 3_ murmur 3 _計算index的hash值

附加類型mapper-attachments可支持_ attachments _ 索引,例如Microsoft office格式,html等


Mapping字段說明

{[if !vml]

[endif]

??? "state": "open",

??? "settings": {[if !vml]

[endif]

??????? "index": {[if !vml]

[endif]

??????????? "creation_date": "1546288211675",

??????????? "number_of_shards": "5",

??????????? "number_of_replicas": "1",

??????????? "uuid": "lUe3u9JvROO4edTro7SDRA",

??????????? "version": {[if !vml]

[endif]

??????????????? "created": "5020299"

??????????? },

??????????? "provided_name": "commodity"

??????? }

??? },

??? "mappings": {[if !vml]

[endif]

??????? "vegetables": {[if !vml]

[endif]

??????????? "properties": {[if !vml]

[endif]

??????????????? "mid": {[if !vml]

[endif]

??????????????????? "type": "text",

??????????????????? "fields": {[if !vml]

[endif]

??????????????????????? "keyword": {[if !vml]

[endif]

??????????????????????????? "ignore_above": 256,

??????????????????????????? "type": "keyword"

??????????????????????? }

??????????????????? }

??????????????? },

??????????????? "title": {[if !vml]

[endif]

??????????????????? "type": "text",

??????????????????? "fields": {[if !vml]

[endif]

??????????????????????? "keyword": {[if !vml]

[endif]

??????????????????????????? "ignore_above": 256,

??????????????????????????? "type": "keyword"

??????????????????????? }

??????????????????? }

??????????????? },

??????????????? "content": {[if !vml]

[endif]

??????????????????? "type": "text",

??????????????????? "fields": {[if !vml]

[endif]

??????????????????????? "keyword": {[if !vml]

[endif]

??????????????????????????? "ignore_above": 256,

??????????????????????????? "type": "keyword"

??????????????????????? }

??????????????????? }

??????????????? }

??????????? }

??????? },

??????? "phone": {[if !vml]

[endif]

??????????? "properties": {[if !vml]

[endif]

??????????????? "mid": {[if !vml]

[endif]

??????????????????? "type": "text",

??????????????????? "fields": {[if !vml]

[endif]

??????????????????????? "keyword": {[if !vml]

[endif]

??????????????????????????? "ignore_above": 256,

??????????????????????????? "type": "keyword"

??????????????????????? }

??????????????????? }

??????????????? },

??????????????? "title": {[if !vml]

[endif]

??????????????????? "type": "text",

??????????????????? "fields": {[if !vml]

[endif]

??????????????????????? "keyword": {[if !vml]

[endif]

??????????????????????????? "ignore_above": 256,

??????????????????????????? "type": "keyword"

??????????????????????? }

??????????????????? }

??????????????? },

??????????????? "content": {[if !vml]

[endif]

??????????????????? "type": "text",

??????????????????? "fields": {[if !vml]

[endif]

??????????????????????? "keyword": {[if !vml]

[endif]

??????????????????????????? "ignore_above": 256,

??????????????????????????? "type": "keyword"

??????????????????????? }

??????????????????? }

??????????????? }

??????????? }

??????? }

??? },

??? "aliases": [ ],

??? "primary_terms": {[if !vml]

[endif]

??????? "0": 1,

??????? "1": 1,

??????? "2": 1,

??????? "3": 1,

??????? "4": 1

??? },

??? "in_sync_allocations": {[if !vml]

[endif]

??????? "0": [[if !vml]

[endif]

??????????? "rcxcuP1kQrelWd935T_xPw"

??????? ],

??????? "1": [[if !vml]

[endif]

??????????? "7mpsfo23RHCUX9w6Rz1jrA"

??????? ],

??????? "2": [[if !vml]

[endif]

??????????? "Pj4yx7sjTnqAdwWkgPNZVQ"

??????? ],

??????? "3": [[if !vml]

[endif]

??????????? "KoHCxlZ7SDOepUjqJzT83g"

??????? ],

??????? "4": [[if !vml]

[endif]

??????????? "Tz6Xavw1Sv6zHNbbmZixCQ"

??????? ]

??? }

}


"store":"false"?????????? 是否單獨設置此字段的是否存儲而從_source字段中分離,默認是false,只能搜索不能取值


"index": "true"?????????? 分詞,不分詞為false


"analyzer":"ik"????? 指定分詞器,默認是standard analyzer


"boost":"1.23"?????????? 字段級別的分數加權,默認是1.0


"doc_values": "false"?????? 對not_analyzed字段,默認都是開啟,分詞字段不能使用,對排序和聚合能提升比較明顯的性能,節(jié)約內存


"fielddata":{ "format":"disabled"}???????? 針對分詞字段,參與排序或聚合時能提升性能,不分詞字段統(tǒng)一建議使用doc_value


"fields":{"keyword":{"ignore_above": 256, "type": "keyword"}}???????? 字段屬性


"ignore_above":256?????? 超過256個字符的文本會被忽略,不被索引


"include_in_all":true??????? 設置是否詞字段包含在_all字段中,默認是true,除非設置no


"index_options":"docs"??????? 4個可選參數,docs(索引文檔號),freqs(文檔號+詞頻),positions(文檔號+詞頻+位置,通常用在距離查詢),offsets(文檔號+詞頻+位置+偏移量,通常用在高亮字段),分詞默認是position,其他的默認為docs


"null_value":"NULL"??????? 缺失字段的初始值,只有string可以使用,分詞字段的null值也會被分詞


"position_increament_gap":"0"?????? 影響距離查詢或近似查詢,可以設置在多值字段的數據上火的分詞字段上,查詢時可用slop間隔,默認值是100


"search_analyer":"ik"????? 設置搜索時的分詞器


"similarity":"BM25"???????? 默認是TF/IDF算法,指定一個字段評分策略,只對字符串類型的分詞有效


"term_vector":"no"???????? 默認不存儲向量信息,支持參數yes(term存儲),with_positions(term+位置),with_offsets(term+偏移量),with_positions_offsets(term+位置+偏移量)對快速高亮fast

vector highlighter能提升性能,但開啟又會加大索引體積,不適合大數據量用。


"dynamic":"true" 動態(tài)映射,當Elasticsearch遇到mapping中沒有的字段,會利用動態(tài)映射來決定字段類型,并自動對該字段添加索引。(true默認,false忽略新字段,strict拋出異常)



Java Api

pom.xml

<projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

?<modelVersion>4.0.0</modelVersion>

?<groupId>com.levi.elasticsearch</groupId>

?<artifactId>elasticsearch</artifactId>

?<version>0.0.1-SNAPSHOT</version>


??? <dependencies>

???????? <dependency>

????????????? <groupId>junit</groupId>

????????????? <artifactId>junit</artifactId>

????????????? <version>3.8.1</version>

????????????? <scope>test</scope>

???????? </dependency>

???????? <dependency>

????????????? <groupId>org.elasticsearch</groupId>

????????????? <artifactId>elasticsearch</artifactId>

????????????? <version>5.2.2</version>

???????? </dependency>


???????? <dependency>

????????????? <groupId>org.elasticsearch.client</groupId>

????????????? <artifactId>transport</artifactId>

????????????? <version>5.2.2</version>

???????? </dependency>


???????? <dependency>

????????????? <groupId>org.apache.logging.log4j</groupId>

????????????? <artifactId>log4j-core</artifactId>

????????????? <version>2.9.0</version>

???????? </dependency>

???? </dependencies>

</project>


App.java

import java.io.IOException;

import java.net.InetAddress;

import java.net.UnknownHostException;

import java.util.HashMap;

import java.util.Iterator;

import java.util.Map;

import java.util.concurrent.ExecutionException;


importorg.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder;

importorg.elasticsearch.action.admin.indices.delete.DeleteIndexRequestBuilder;

importorg.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;

importorg.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse;

importorg.elasticsearch.action.bulk.BulkRequestBuilder;

import org.elasticsearch.action.bulk.BulkResponse;

importorg.elasticsearch.action.delete.DeleteRequestBuilder;

importorg.elasticsearch.action.get.GetRequestBuilder;

importorg.elasticsearch.action.get.MultiGetItemResponse;

importorg.elasticsearch.action.get.MultiGetRequestBuilder;

import org.elasticsearch.action.index.IndexRequest;

importorg.elasticsearch.action.index.IndexResponse;

importorg.elasticsearch.action.search.SearchRequestBuilder;

importorg.elasticsearch.action.search.SearchResponse;

importorg.elasticsearch.action.update.UpdateRequest;

importorg.elasticsearch.action.update.UpdateResponse;

import org.elasticsearch.client.Requests;

importorg.elasticsearch.client.transport.TransportClient;

import org.elasticsearch.common.settings.Settings;

import org.elasticsearch.common.transport.InetSocketTransportAddress;

importorg.elasticsearch.common.xcontent.XContentBuilder;

importorg.elasticsearch.common.xcontent.XContentFactory;

import org.elasticsearch.index.query.QueryBuilders;

import org.elasticsearch.search.SearchHit;

import org.elasticsearch.search.SearchHits;

importorg.elasticsearch.transport.client.PreBuiltTransportClient;

import org.junit.After;

import org.junit.Before;

import org.junit.Test;


/**

?*集群健康值

?* ES存儲數據也是按照切片的方式,默認是5個切片,而且切片都是有副本的

?* ES服務默認端口是9300

?* ES-Web管理端口9200

?* ES的2.x系列的版本和5.x版本或以上的Api區(qū)別在于內部數個組件的整合,

?*使得版本兼容不在痛苦,所以一下子2.X版本直接到5.X版本

?*@author AimSpeed

?*@Projectelasticsearch

?*@Package com.levi.elasticsearch

?*@FileName App.java

?*@ClassNameApp

?*@date 2018年12月31日 下午7:33:59

?*/

public class App {


???? private TransportClient transportClient;

/**

???? ?*獲取客戶端對象

???? ?*@author AimSpeed

???? ?*@throwsUnknownHostException??

???? ?*@TitlegetClient? void?

???? ?*@date 2018年12月31日 下午7:44:35

???? ?*/

???? @Before

???? public void getClient() throwsUnknownHostException? {

???????? //設置集群名稱

???????? Settingssettings= Settings.builder().put("cluster.name","my-application").build();


???????? //獲取客戶端對象

???????? transportClient = new PreBuiltTransportClient(settings);


???????? //具體要連接的集群地址,是一個可變參數,多臺服務器就填寫多個地址

???????? transportClient.addTransportAddress(newInetSocketTransportAddress(InetAddress.getByName("192.168.1.110"),

???????????????????????????????????????????????????????????????????????????????????????? 9300));


???????? System.out.println(transportClient);

???? }


???? /**

???? ?*執(zhí)行完之后關閉資源

???? ?*@author AimSpeed

???? ?*@TitlecloseClient? void?

???? ?*@date 2018年12月31日 下午8:28:47

???? ?*/

???? @After

???? public void closeClient() {

???????? //關閉資源

???????? transportClient.close();

???????? System.out.println("成功,關閉資源!");

???? }


???? /**

???? ?*創(chuàng)建索引 = 數據庫

???? ?*可在圖形化界面查看

???? ?*@author AimSpeed

???? ?*@TitlecreateIndex? void?

???? ?*@date 2018年12月31日 下午7:55:38

???? ?*/

???? @Test

???? public void createIndex() {

???????? //創(chuàng)建一個商品索引(商品數據庫)

???????? CreateIndexRequestBuilderrequest = transportClient.admin().indices().prepareCreate("commodity");


???????? System.out.println(request.get().isAcknowledged());

???? }


???? /**

???? ?*刪除索引 = 數據庫

???? ?*可在圖形化界面查看

???? ?*@author AimSpeed

???? ?*@TitledelIndex? void?

???? ?*@date 2018年12月31日 下午8:26:01

???? ?*/

???? @Test

???? public void delIndex() {

???????? DeleteIndexRequestBuilderrequest = transportClient.admin().indices().prepareDelete("commodity");

???????? System.out.println(request.get().isAcknowledged());

???? }


???? //=========================================================

?

???? /**

???? ?*以json的方式插入文檔

???? ?*@author AimSpeed

???? ?*@TitlecreateDocumentByJson? void?

???? ?*@date 2018年12月31日 下午8:41:27

???? ?*/

???? @Test

???? public void createDocumentByJson() {

???????? //數據

???????? Stringjson = "{" + "\"mid\":\"A\"," + "\"title\":\"00年諾基亞\","

?????????????????? +"\"content\":\"耐砸\"" + "}";


???????? //插入數據

???????? //index(索引 = 庫)????? type(類型 = 表)


???????? //手動插入Id

???????? //IndexResponse response =

transportClient.prepareIndex("commodity", "phone",

"1")

???????????????????????????????????????????????????????????? //.setSource(json).execute().actionGet();


???????? //自動生成內部Id

???????? IndexResponseresponse = transportClient.prepareIndex("commodity", "phone")

??????????????????????????????????????????????????????? .setSource(json).execute().actionGet();


???????? System.out.println("位于的索引(庫):" + response.getIndex());

???????? System.out.println("位于的類型(表):" + response.getType());

???????? System.out.println("版本:" + response.getVersion());

???????? System.out.println("Id:" + response.getId());

???????? System.out.println("結果:" + response.getResult());

???? }


???? /**

???? ?*以Map的方式插入數據

???? ?*@author AimSpeed

???? ?*@TitlecreateDocumentByMap? void?

???? ?*@date 2018年12月31日 下午9:06:19

???? ?*/

???? @Test

???? public void createDocumentByMap() {

???????? //數據

???????? Mapmap = new HashMap<String, Object>();

???????? map.put("mid", "A");

???????? map.put("title", "花菜");

???????? map.put("content", "送給女的,會給打么?");


???????? //插入數據

???????? //index(索引 = 庫)????? type(類型 = 表)

???????? IndexResponseresponse = transportClient.prepareIndex("commodity", "vegetables")

??????????????????????????????????????????????????????? .setSource(map).execute().actionGet();


???????? System.out.println("位于的索引(庫):" + response.getIndex());

???????? System.out.println("位于的類型(表):" + response.getType());

???????? System.out.println("版本:" + response.getVersion());

???????? System.out.println("Id:" + response.getId());

???????? System.out.println("結果:" + response.getResult());


???? }

?

???? /**

???? ?*以Builder方式插入數據

???? ?*@author AimSpeed

???? ?*@Title createDocumentByBuilder

???? ?*@throwsIOException void?

???? ?*@date 2018年12月31日 下午9:15:59

???? ?*/

???? @Test

???? public void createDocumentByBuilder() throws IOException {

???????? //數據

???????? XContentBuilderbuilder= XContentFactory.jsonBuilder()

???????????????????????????????????????????????????????????????? .startObject()

????????????????????????????????????????????????????????????????????? .field("mid","B")

????????????????????????????????????????????????????????????????????? .field("title", "三防手機")

????????????????????????????????????????????????????????????????????? .field("content","能抵擋洪水?")

???????????????????????????????????????????????????????????????? .endObject();


???????? //插入數據,自定義ES內部ID。

???????? IndexResponseresponse = transportClient.prepareIndex("commodity", "phone","2")

??????????????????????????????????????????????????????? .setSource(builder).execute().actionGet();


???????? System.out.println("位于的索引(庫):" + response.getIndex());

???????? System.out.println("位于的類型(表):" + response.getType());

???????? System.out.println("版本:" + response.getVersion());

???????? System.out.println("Id:" + response.getId());

???????? System.out.println("結果:" + response.getResult());


???? }


???? /**

???? ?*批量插入

???? ?*@author AimSpeed

???? ?*@Title createBulkDocument

???? ?*@throwsException void?

???? ?*@date 2018年12月31日 下午10:54:11

???? ?*/

???? @Test

???? public void createBulkDocument() throws Exception {

???????? //批量操作對象

???????? BulkRequestBuilderprepareBulk = transportClient.prepareBulk();


???????? //第1條數據

???????? prepareBulk.add(transportClient.prepareIndex("commodity", "phone")

?????????????????????????????????????????????? .setSource(XContentFactory.jsonBuilder()

???????????????????????????????????????????????????????????????? .startObject()

???????????????????????????????????????????????????????????????? .field("mid","E")

???????????????????????????????????????????????????????????????? .field("title", "6防手機")

???????????????????????????????????????????????????????????????? .field("content","能抵擋洪水?")

???????????????????????????????????????????????????????????? .endObject()));


???????? //第2條數據

???????? prepareBulk.add(transportClient.prepareIndex("commodity", "phone")

?????????????????????????????????????????????? .setSource(XContentFactory.jsonBuilder()

???????????????????????????????????????????????????????????????? .startObject()

???????????????????????????????????????????????????????????????? .field("mid","F")

???????????????????????????????????????????????????????????????? .field("title", "99防手機")

???????????????????????????????????????????????????????????????? .field("content","能抵擋洪水?")

??????????????????????????????????????????????????????? ???? .endObject()));


???????? BulkResponseresponse = prepareBulk.get();

???????? System.out.println("是否有失敗數據:" + response.hasFailures());

???? }


???? //=========================================================

????

???? /**

???? ?*搜索文檔(單個)

???? ?*@author AimSpeed

???? ?*@TitlequeryById? void?

???? ?*@date 2018年12月31日 下午9:18:55

???? ?*/

???? @Test

???? public void queryById () {

???????? //內部ID,作為搜索索引

???????? //GetRequestBuilder request =

transportClient.prepareGet("commodity", "phone",

"AWgGAaE6zc8qunjZLZcr");


???????? //自定義插入的ID,作為搜索索引

???????? GetRequestBuilderrequest = transportClient.prepareGet("commodity", "phone", "1");


???????? System.out.println(request.get().getSourceAsString());

???? }


???? /**

???? ?*多個ID查詢

???? ?*@author AimSpeed

???? ?*@TitlequeryByMultiId? void?

???? ?*@date 2018年12月31日 下午9:25:41

???? ?*/

???? @Test

???? public void queryByMultiId() {

???????? MultiGetRequestBuildermultiGetRequestBuilder = transportClient.prepareMultiGet()

????????????????????????????????????????????????????????????????????? .add("commodity", "phone", "1")//自定義的id

????????????????????????????????????????????????????????????????????? .add("commodity", "phone", "AWgGAaE6zc8qunjZLZcr","2");//多個id,可變參數

???????? for (MultiGetItemResponse response : multiGetRequestBuilder.get()) {

????????????? if(response.getResponse().isExists()) {

?????????????????? System.out.println(response.getResponse().getSourceAsString());

????????????? }

???????? }???????????????????????????????????????????????????????????

???? }


???? /**

???? ?*查找所有

???? ?*@author AimSpeed

???? ?*@TitlequeryMatch? void?

???? ?*@date 2018年12月31日 下午9:27:30

???? ?*/

???? @Test

???? public void queryMatch() {

???????? //任何的Api,在使用的時候注意下傳入的參數,可能是可變形參

???????? SearchRequestBuilderrequest = transportClient.prepareSearch("commodity").setTypes("phone","vegetables")

???????????????????????????????????????????????????????????? .setQuery(QueryBuilders.matchAllQuery());


???????? //查詢結果

???????? SearchHitshits = request.get().getHits();


???????? System.out.println("查詢結果數量: " + hits.getTotalHits());


???????? //打印結果

???????? Iteratoriterator = hits.iterator();

???????? while(iterator.hasNext()) {

????????????? SearchHitsearchHit = iterator.next();

????????????? System.out.println(searchHit.getSourceAsString());

???????? }

???? }

????

???? /**

???? ?*分詞查詢

???? ?*@author AimSpeed

???? ?*@TitlequeryByParticiple? void?

???? ?*@date 2018年12月31日 下午9:36:11

???? ?*/

???? @Test

???? public void queryByParticiple() {

???????? //查詢語句

???????? SearchResponseresponse = transportClient.prepareSearch("commodity").setTypes("phone","vegetables")

???????????????????????????????????????????????????????????? .setQuery(QueryBuilders.queryStringQuery("拍照")).get();

???????? //查詢結果

???????? SearchHitshits = response.getHits();


???????? System.out.println("查詢結果數量:" + hits.getTotalHits());


???????? //打印結果

???????? Iteratoriterator = hits.iterator();

???????? while(iterator.hasNext()) {

????????????? SearchHithit = iterator.next();

????????????? System.out.println(hit.getSourceAsString());

???????? }


???? }


???? /**

???? ?*詞條搜索

???? ?*@author AimSpeed

???? ?*@TitlequeryByTerm? void?

???? ?*@date 2018年12月31日 下午9:42:17

???? ?*/

???? @Test

???? public void queryByTerm() {

???????? //查詢語句

???????? SearchResponseresponse = transportClient.prepareSearch("commodity").setTypes("phone","vegetables")

????????????????????????????????????????? //會發(fā)現查詢不到,詞條查詢就是詞查詢,每個字作為索引的(切分成一個個的詞),除非引入分詞器(ik分詞器等)?????????????????

????????????????????????????????????????? //.setQuery(QueryBuilders.termQuery("content",

"拍照")).get();

????????????????????????????????????????? .setQuery(QueryBuilders.termQuery("content", "拍")).get();


???????? //查詢結果對象

???????? SearchHitssearchHits = response.getHits();

???????? System.out.println("查詢結果數量:" + searchHits.getTotalHits());


???????? //遍歷打印

???????? Iteratoriterator = searchHits.iterator();


???????? while(iterator.hasNext()) {

????????????? System.out.println(iterator.next().getSourceAsString());

???????? }


???? }


???? /**

???? ?*通配符查詢

???? ?* *多個字符

???? ?* ?單個字符

???? ?*@author AimSpeed

???? ?*@TitlequeryByWildcard? void?

???? ?*@date 2018年12月31日 下午9:49:24

???? ?*/

???? @Test

???? public void queryByWildcard() {

???????? //查詢語句

???????? SearchResponseresponse = transportClient.prepareSearch("commodity").setTypes("phone","vegetables")

????????????????????????????????????????? .setQuery(QueryBuilders.wildcardQuery("content", "玩*")).get();


???????? //查詢結果對象

???????? SearchHitssearchHits = response.getHits();

???????? System.out.println("查詢結果數量:" + searchHits.getTotalHits());


???????? //遍歷打印

???????? Iteratoriterator = searchHits.iterator();


???????? while(iterator.hasNext()) {

????????????? System.out.println(iterator.next().getSourceAsString());

???????? }


???? }

????

???? /**

???? ?*模糊查詢

???? ?*@author AimSpeed

???? ?*@TitlequeryByLike? void?

???? ?*@date 2018年12月31日 下午9:53:17

???? ?*/

???? @Test

???? public void queryByLike() {

???????? //查詢語句

???????? SearchResponseresponse = transportClient.prepareSearch("commodity").setTypes("phone","vegetables")

????????????????????????????????????????? .setQuery(QueryBuilders.fuzzyQuery("content", "游")).get();


???????? //查詢結果對象

???????? SearchHitssearchHits = response.getHits();

???????? System.out.println("查詢結果數量:" + searchHits.getTotalHits());


???????? //遍歷打印

???????? Iteratoriterator = searchHits.iterator();


???????? while(iterator.hasNext()) {

????????????? System.out.println(iterator.next().getSourceAsString());

???????? }

???? }


???? //=========================================================


???? /**

???? ?*更新數據

???? ?*@author AimSpeed

???? ?*@Title update

???? ?*@throws IOException

???? ?*@throws InterruptedException

???? ?*@throwsExecutionException void?

???? ?*@date 2018年12月31日 下午10:38:21

???? ?*/

???? @Test

???? public void update() throws IOException, InterruptedException,

ExecutionException {

???????? //創(chuàng)建更新數據的請求對象

???????? UpdateRequestupdateRequest = new UpdateRequest("commodity", "phone", "1");



???????? //更新

???????? updateRequest.doc(XContentFactory.jsonBuilder()

?????????????????????????????????????????????????? .startObject()

??????????????????????????????????????????????????????? .field("content","更新...")

?????????????????????????????????????????????????? .endObject());


???????? UpdateResponseresponse = transportClient.update(updateRequest).get();


???????? System.out.println("位于的索引(庫):" + response.getIndex());

???????? System.out.println("位于的類型(表):" + response.getType());

???????? System.out.println("版本:" + response.getVersion());

???????? System.out.println("Id:" + response.getId());

???????? System.out.println("結果:" + response.getResult());

???? }

?

???? /**

???? ?*更新數據,如果不存在就添加數據

???? ?*@author AimSpeed

???? ?*@Titleupsert? void?

???? ?*@date 2018年12月31日 下午10:38:56

???? ?*/

???? @Test

???? public void upsert() throws IOException, InterruptedException, ExecutionException

{

???????? //沒有這個文檔就創(chuàng)建

???????? //索引??????類型??????? 內部id(可自動生成)

//?????? IndexRequestindexRequest = new IndexRequest("commodity", "phone");

???????? IndexRequestindexRequest = new IndexRequest("commodity", "phone", "5");


???????? indexRequest.source(XContentFactory.jsonBuilder()

??????????????????????????????????????????????????????? .startObject()

???????????????????????????????????????????????????????????? .field("mid","D")

???????????????????????????????????????????????????????????? .field("title","不存在的數據,無法更新,那就添加")

??????????????????????????????????????????????????????? .endObject());


???????? UpdateRequestupdateRequest = new UpdateRequest("commodity", "phone", "6");

???????? //更新

???????? updateRequest.doc(XContentFactory.jsonBuilder()

?????????????????????????????????????????????????? .startObject()

??????????????????????????????????????????????????????? .field("content","upsert() 更新...")

?????????????????????????????????????????????????? .endObject());


???????? //更新失敗就添加

???????? updateRequest.upsert(indexRequest);


???????? //更新

???????? UpdateResponseresponse = transportClient.update(updateRequest).get();


???????? System.out.println("位于的索引(庫):" + response.getIndex());

???????? System.out.println("位于的類型(表):" + response.getType());

???????? System.out.println("版本:" + response.getVersion());

???????? System.out.println("Id:" + response.getId());

???????? System.out.println("結果:" + response.getResult());


???????? //注意看頁面的結果id列,很有趣。


???? }


???? //=========================================================


???? @Test

???? public void delDocument() {

???????? DeleteRequestBuilderrequest = transportClient.prepareDelete("commodity", "phone", "6");

???????? System.out.println(request.get().getResult());

???? }


???? //=========================================================

????

???? /**

???? ?*創(chuàng)建映射 = 約束

???? ?*@author AimSpeed

???? ?*@throws IOException

???? ?*@throws ExecutionException

???? ?*@throws InterruptedException

???? ?*@TitlecreateMapping? void?

???? ?*@date 2018年12月31日 下午10:17:53

???? ?*/

???? @Test

???? public void createMapping() throws IOException,

InterruptedException, ExecutionException {

???????? //定義映射 = 約束

???????? XContentBuilderxContentBuilder= XContentFactory.jsonBuilder()

?????????????????????????????????????????????????? .startObject()

??????????????????????????????????????????????????????? .startObject("fruits")

???????????????????????????????????????????????????????????? .startObject("properties")

???????????????????????????????????????????????????????????????? .startObject("mid")

????????????????????????????????????????????????????????????????????? .field("type","string")

???????????????????????????????????? ???????????????????????????????? .field("store","yes")

???????????????????????????????????????????????????????????????? .endObject()

???????????????????????????????????????????????????????????????? .startObject("title")

????????????????????????????????????????????????????????????????????? .field("type","string")

????????????????????????????????????????????????????????????????????? .field("store","no")

???????????????????????????????????????????????????????????????? .endObject()

???????????????????????????????????????????????????????????????? .startObject("content")

????????????????????????????????????????????????????????????????????? .field("type","string")

????????????????????????????????????????????????????????????????????? .field("store","yes")

???????????????????????????????????????????????????????????????? .endObject()

???????????????????????????????????????????????????????????? .endObject()

??????????????????????????????????????????????????????? .endObject()

?????????????????????????????????????????????????? .endObject();


???????? //添加索引

???????? PutMappingRequestmapping= Requests.putMappingRequest("commodity2")

???????????????????????????????????? ????????????? .type("fruits").source(xContentBuilder);


???????? //添加

???????? PutMappingResponseputMappingResponse = transportClient.admin().indices().putMapping(mapping).get();


???????? System.out.println(putMappingResponse.isAcknowledged());


???? }

}

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,786評論 6 534
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 98,656評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,697評論 0 379
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,098評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,855評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,254評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,322評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,473評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 49,014評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,833評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,016評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,568評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,273評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,680評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,946評論 1 288
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,730評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,006評論 2 374

推薦閱讀更多精彩內容