elasticSearch入门到java操作api一套搞定
目錄
寫在前面
一、下載地址
二、solr與es比較
三、安裝elasticsearch
四、安裝可視化界面(hand插件)
使用
五、安裝kibana
六、學習es核心概念
七、IK分詞器插件
八、使用ES
九、es的復雜查詢
十、集成Springboot
十一、京東搜索
寫在前面
ES(ElasticSearch)相信很多小伙伴都聽過它的鼎鼎大名,但是一直不知道其是如何工作的,今天就靠這一篇文章將它徹底入門!
一、下載地址
因為ES及其部分插件,國內下載速度比較慢,這里貼出來華為云的下載鏈接,速度剛剛的!
ElasticSearch: https://mirrors.huaweicloud.com/elasticsearch/?C=N&O=D
logstash: https://mirrors.huaweicloud.com/logstash/?C=N&O=D
kibana: https://mirrors.huaweicloud.com/kibana/?C=N&O=D
elasticsearch-analysis-ik: https://github.com/medcl/elasticsearch-analysis-ik/releases
cerebro: https://github.com/lmenezes/cerebro/releases
head:https://github.com/mobz/elasticsearch-head
二、solr與es比較
1.es基本開箱即用(解壓就可以用!),非常簡單。Solr安裝稍微復雜一丟丟!
2.Solr利用Zookeeper進行分布式管理,而Es自身帶有分布式協調管理功能。
3.Solr支持更多格式的數據,比如JSON、XML、CSV,而Es僅支持json文件格式。
4.Solr官方提供的功能更多,而Elasticsearch本身更注重核心功能,高級功能多有第三方插件提供,例如圖形化界面需要kibana友好支撐。
5.Solr查詢塊,但更新索引時慢(即插入刪除慢),用于電商等查詢多的應用;
? ? ES建立索引快(即查詢慢),即實時性查詢塊,用于facebook新浪等搜索;
? ? Solr是傳統搜索應用的有力解決方案,但Elasticsearch更適用于新興的實時搜索應用。
6.Solr比較成熟,有一個更大,更成熟的用戶、開發和貢獻者社區,而Elasticsearch相對開發維護者較少,更新太快,學習使用成本較高。
三、安裝elasticsearch
要求:jdk1.8以上。
1.解壓即可使用。
jvm.options是jvm的配置文件,默認內存1G。
elasticsearch.yml是es的配置文件,默認9200端口,通信端口是9300。
modules是功能模塊。
plugins是第三方插件。
2.啟動。
雙擊bin/elasticsearch.bat
3.輸入網址
http://localhost:9200/
{"name" : "DESKTOP-BA2JN2H","cluster_name" : "elasticsearch","cluster_uuid" : "BJx-AEKcQoacSXfZhpCI5A","version" : {"number" : "7.6.0","build_flavor" : "default","build_type" : "zip","build_hash" : "7f634e9f44834fbc12724506cc1da681b0c3b1e3","build_date" : "2020-02-06T00:09:00.449973Z","build_snapshot" : false,"lucene_version" : "8.4.0","minimum_wire_compatibility_version" : "6.8.0","minimum_index_compatibility_version" : "6.0.0-beta1"},"tagline" : "You Know, for Search" }四、安裝可視化界面(hand插件)
1.必須安裝node.js。
2.npm安裝
* git clone git://github.com/mobz/elasticsearch-head.git * cd elasticsearch-head * npm install * npm run start * open http://localhost:9100/3.解決es跨域問題
elasticsearch.yml配置文件
http.cors.enabled: true http.cors.allow-origin: "*"4.打開http://localhost:9100/
連接http://localhost:9200/
使用
5.初學,就把es當做一個數據庫。索引就相當于一個數據庫,文檔就相當于數據。
? ? 這個hand把它當成一個數據展示工具,后面所有的查詢可以在kibana做。
五、安裝kibana
kibana版本要和es版本一致!
1.解壓。
2.啟動(也需要安裝node.js)
bin/kibana.bat
3.訪問http://localhost:5601
4.漢化
\kibana-7.6.0-windows-x86_64\x-pack\plugins\translations\translations\下面有漢化文件。
config/kibana.yml下配置:
i18n.locale: "zh-CN"5.開發工具
六、學習es核心概念
1.elasticsearch是面向文檔的數據庫。關系型數據庫和elasticsearch客觀的對比:
| Relational?DB(MySQL) | Elasticsearch |
| 數據庫(database) | 索引(indices)(就和數據庫一樣) |
| 表(tables) | 類型types(慢慢會被棄用) |
| 行(rows) | 文檔documents |
| 字段(columns) | 字段fields |
? ? elasticsearch(集群)中可以包含多個索引(數據庫),每個索引中可以包含多個類型(表),每個類型下又包含多個文檔(行),每個文檔中又包含多個字段(列)。
2.物理設計
? ? elasticsearch在后臺把每個索引劃分成多個分片,每分分片可以在集群中的不同服務器間遷移。
? ? 一個人就是一個集群!默認的集群名稱就是elasticsearch。
3.邏輯設計
? ? 一個索引類型中,包含多個文檔,比如說文檔1,文檔2。當我們索引一篇文檔時,可以通過這樣的一個順序找到它:索引 ->類型 ->?文檔ID,通過這個組合我們就能索引到某個具體的文檔。注意:ID不必是整數,實際上它是個字符串。
①文檔(就是一條條數據):
?? ?之前說 elasticsearch是面向文檔的,那么就意味著索引和搜索數據的最小單位是文檔,elasticsearch中,文檔有幾個重要屬性:
? ? (1)自我包含,一篇文檔同時包含字段和對應的值,也就是同時包含 key: value!
? ? (2)可以是層次型的,一個文檔中包含自文檔,復雜的邏輯實體就是這么來的!{就是一個json對象!}
? ? (3)靈活的結構,文檔不依賴預先定義的模式,我們知道關系型數據庫中,要提前定義字段才能使用,在elasticsearch中,對于字段是非常靈活的,有時候,我們可以忽略該字段,或者動態的添加一個新的字段。? ?
?? ?盡管我們可以隨意的新増或者忽略某個字段,但是,每個字段的類型非常重要,比如一個年齡字段類型,可以是字符串也可以是整形。因為 elasticsearch會保存字段和類型之間的映射及其他的設置。這種映射具體到毎個映射的每種類型,這也是為什么在elasticsearch中,類型有時候也稱為映射類型。
②類型(較少去用了)
? ? 類型是文檔的邏輯容器,就像關系型數據庫一樣,表格是行的容器。類型中對于字段的定義稱為映射,比如name映射為字符串類型。我們說文檔是無模式的,它們不需要擁有映射中所定義的所有字段,比如新增一個字段,那么 elasticsearch是怎么做的呢?elasticsearch會自動的將新字段加入映射,但是這個字段的不確定它是什么類型, elasticsearch就開始猜,如果這個值是18,那么elasticsearch會認為它是整形。但是 elastirsearch也可能猜不對,所以最安全的方式就是提前定義好所需要的映射,這點跟關系型數據庫殊途同歸了,先定義好字段,然后再使用,別整什么幺蛾子。
③索引
?? ?索引就是數據庫!
?? ?索引是映射類型的容器, elasticsearch中的索引是一個非常大的文檔集合。索引存儲了映射類型的字段和其他設置。然后它們被存儲到了各個分片上了。我們來研究下分片是如何工作的。
4.物理設計:節點和分片如何工作
? ? 一個集群至少有一個節點,,而一個節點就是一個 elasticsearch進程,節點可以有多個索引默認的,如果你創建索引,那么索引將會有個5個分片( primary shard,又稱主分片)構成的,每一個主分片會有一個副本( replica shard,又稱復制分片)
?? ?上圖是一個有3個節點的集群,可以看到主分片和對應的復制分片都不會在同一個節點內,這樣有利于某個節點掛掉了,數據也不至于丟失。實際上,一個分片是一個 Lucene索引,一個包含倒排索引圖的文件目錄,倒排索引的結構使得 elasticsearch在不掃描全部文檔的情況下,就能告訴你哪些文檔包含特定的關鍵字。不過,等等,倒排索引是什么鬼?
5.倒排索引
?? ?elasticsearch使用的是一種稱為倒排索引的結構,采用 Lucene倒排索作為底層。這種結構適用于快速的全文搜索,一個索引由文檔中所有不重復的列表構成,對于每一個詞,都有一個包含它的文檔列表。例如,現在有兩個文檔,每個文檔包含如下內容:
?? ?為了創建倒排索引,我們首先要將每個文檔拆分成獨立的詞(或稱為詞條或者 tokens),然后創建一個包含所有不重復的詞條的排序列表,然后列出每個詞條出現在哪個文檔。
? ? 現在我們試圖搜索to?forever,只需要查看包含每個詞條的文檔。
?? ?兩個文檔都匹配,但是第一個文檔比第二個匹配程度更高。如果沒有別的條件,現在,這兩個包含關鍵字的文檔都將返回。
?? ?再來看一個示例,比如我們通過博客標簽來搜索博客文章。那么倒排索引列表就是這樣的一個結構:
?? ?如果要搜索含有 python標簽的文章,那相對于査找所有原始數據而言,査找倒排索引后的數據將會快的多。只需要査看標簽這欄,然后獲取相關的文章ID即可。完全過濾掉無關的所有數據,提高效率!
?? ?elasticsearch的索引和 Lucene的索引對比:
?? ?在 elasticsearch中,索引這個詞被頻繁使用,這就是術語的使用。在 elasticsearch中,索引被分為多個分片,每份分片是一個Lucene的索引。所以一個 elasticsearch索引是由多個 Lucene索引組成的。別問為什么,誰讓 elasticsearchy使用 Lucene作為底層呢!如無特指,說起索引都是指 elasticsearch的索引。
七、IK分詞器插件
1.什么是IK分詞器
?? ?分詞:即把一段中文或者別的劃分成一個個的關鍵字,我們在搜索時候會把自己的信息進行分詞,會把數據庫中或者索引庫中的數據進行分詞,然后進行—個匹配操作,默認的中文分詞是將毎個字看成一個詞,比如“我愛狂神”會被分為"我""愛""狂"神",這顯然是不符合要求的,所以我們需要安裝中文分詞器IK來解決這個問題。
? ? 如果要使用中文,建議使用IK分詞器!
? ? IK提供了兩個分詞算法: ik_smart和 ik_max_word,其中 ik_smart為最少切分,ik_max_word為最細粒度劃分!
2.下載安裝(下載與es對應的版本!!!否則會啟動報錯)
①下載完,解壓到ES目錄下
D:\es\elasticsearch-7.6.0\plugins\elasticsearch-analysis-ik-7.6.0
②重啟es,會出現加載ik插件
[2021-05-07T09:51:29,253][INFO ][o.e.p.PluginsService ] [DESKTOP-KAO1R1F] loaded plugin [analysis-ik]③使用elasticsearch-plugin.bat,查看插件
3.使用kibana測試
GET _analyze {"analyzer" : "ik_smart","text" : "中國共產黨" }{"tokens" : [{"token" : "中國共產黨","start_offset" : 0,"end_offset" : 5,"type" : "CN_WORD","position" : 0}] } GET _analyze {"analyzer" : "ik_max_word","text" : "中國共產黨" }{"tokens" : [{"token" : "中國共產黨","start_offset" : 0,"end_offset" : 5,"type" : "CN_WORD","position" : 0},{"token" : "中國","start_offset" : 0,"end_offset" : 2,"type" : "CN_WORD","position" : 1},{"token" : "國共","start_offset" : 1,"end_offset" : 3,"type" : "CN_WORD","position" : 2},{"token" : "共產黨","start_offset" : 2,"end_offset" : 5,"type" : "CN_WORD","position" : 3},{"token" : "共產","start_offset" : 2,"end_offset" : 4,"type" : "CN_WORD","position" : 4},{"token" : "黨","start_offset" : 4,"end_offset" : 5,"type" : "CN_CHAR","position" : 5}] }②有些詞被拆分了,需要自己來配置分詞
重啟es看細節
[2021-05-07T10:21:48,875][INFO ][o.e.g.GatewayService ] [DESKTOP-KAO1R1F] recovered [5] indices into cluster_state [2021-05-07T10:21:49,223][INFO ][o.w.a.d.Monitor ] [DESKTOP-KAO1R1F] try load config from D:\es\elasticsearch-7.6.0\config\analysis-ik\IKAnalyzer.cfg.xml [2021-05-07T10:21:49,228][INFO ][o.w.a.d.Monitor ] [DESKTOP-KAO1R1F] try load config from D:\es\elasticsearch-7.6.0\plugins\elasticsearch-analysis-ik-7.6.0\config\IKAnalyzer.cfg.xml [2021-05-07T10:21:49,751][INFO ][o.w.a.d.Monitor ] [DESKTOP-KAO1R1F] [Dict Loading] D:\es\elasticsearch-7.6.0\plugins\elasticsearch-analysis-ik-7.6.0\config\cxf.dic八、使用ES
1.基本REST
2.基礎索引測試
①創建索引
格式: PUT /索引名/(類型名,以后可能不會用到了)/文檔id {請求體}示例: PUT /test1/type1/1 {"name" : "永遠的神","age" : 3 }#! Deprecation: [types removal] Specifying types in document index requests is deprecated, use the typeless endpoints instead (/{index}/_doc/{id}, /{index}/_doc, or /{index}/_create/{id}). {"_index" : "test1","_type" : "type1","_id" : "1","_version" : 1,"result" : "created","_shards" : {"total" : 2,"successful" : 1,"failed" : 0},"_seq_no" : 0,"_primary_term" : 1 }? ? 完成了自動增加了索引!數據也添加成功了!索引初期可以當做一個數據庫!
②指定字段的類型
text類型會被分詞解析,keyword是不會被分詞解析的!
創建規則: PUT /test2 {"mappings": {"properties": {"name" : {"type" :"text"},"age" : {"type" : "long"},"birthday" : {"type" : "date"}}} }③獲得數據信息
GET /test2
④查看默認的信息
如果沒有指定字段類型,那么es會自動設置默認的字段類型
PUT /test3/_doc/1 {"name" : "張三","age" : 18 }使用GET: GET /test3 結果: {"test3" : {"aliases" : { },"mappings" : {"properties" : {"age" : {"type" : "long"},"name" : {"type" : "text","fields" : {"keyword" : {"type" : "keyword","ignore_above" : 256}}}}},"settings" : {"index" : {"creation_date" : "1620355778195","number_of_shards" : "1","number_of_replicas" : "1","uuid" : "b4ATwfKGQ9yoNgB2ce-UOA","version" : {"created" : "7060099"},"provided_name" : "test3"}}} } 獲取健康狀態 GET _cat/health1620356456 03:00:56 elasticsearch yellow 1 1 12 12 0 0 8 0 - 60.0%查看信息 GET _cat/indices?vhealth status index uuid pri rep docs.count docs.deleted store.size pri.store.size yellow open test2 n1Yl5LvZSlyGrsirb3JyrQ 1 1 0 0 283b 283b yellow open test3 b4ATwfKGQ9yoNgB2ce-UOA 1 1 1 0 3.7kb 3.7kb green open .kibana_task_manager_1 uwnOx-ktSl-kLenHmgyQhg 1 0 2 0 13kb 13kb green open .apm-agent-configuration ESfhRweTTxOjx_5NFH0V7Q 1 0 0 0 283b 283b green open kibana_sample_data_flights RXgt4tWjQNqbAMEZnleV3g 1 0 13059 0 6.2mb 6.2mb green open .kibana_1 w_wKw0LxQEitRAWALeQSng 1 0 80 3 136.9kb 136.9kb yellow open test1 SCHGcDpZRYGvTGhhXjqaEg 1 1 1 0 3.7kb 3.7kb yellow open db r1AqWtE1Q_i2I4kwcpMvZQ 5 1 0 0 1.3kb 1.3kb⑤修改
1.直接覆蓋: PUT /test3/_doc/1 {"name" : "李四","age" : 18 }修改之后版本號會+12.使用POST修改 POST /test3/_doc/1/_update {"doc" : {"name" : "王五"} }⑥刪除
DELETE /test3/_doc/1DELETE /test33.關于文檔的操作
①添加數據:
PUT /cxf/user/1 {"name" : "張三","age" : 24,"desc" : "永遠的神","tags" : ["強", "溫暖", "博愛"] }PUT /cxf/user/2 {"name" : "張四","age" : 25,"desc" : "永遠的2","tags" : ["旅游", "玩游戲", "渣男"] }PUT /cxf/user/3 {"name" : "張五","age" : 22,"desc" : "永遠的5","tags" : ["玩", "逛街", "帥b"] }②獲取數據:
GET /cxf/user/3③更新數據:
PUT是完全覆蓋,POST修改是修改指定的屬性
PUT /cxf/user/3 {"name" : "張四2","age" : 25,"desc" : "永遠的2","tags" : ["旅游", "玩游戲", "渣男"] }POST /cxf/user/3/_update {"doc" : {"name" : "張四4"} }九、es的復雜查詢
查詢出來的東西:
hits:索引和文檔的信息。
total:查詢結果總數。
然后就是查詢出來的具體文檔。
數據中的東西都可以遍歷出來了。
分數:我們可以通過來判斷誰更加符合結果。
#! Deprecation: [types removal] Specifying types in search requests is deprecated. {"took" : 2,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 3,"relation" : "eq"},"max_score" : 0.6409958,"hits" : [{"_index" : "cxf","_type" : "user","_id" : "2","_score" : 0.6409958,"_source" : {"name" : "張四","age" : 25,"desc" : "永遠的2","tags" : ["旅游","玩游戲","渣男"]}},{"_index" : "cxf","_type" : "user","_id" : "3","_score" : 0.5403744,"_source" : {"name" : "張四4","age" : 25,"desc" : "永遠的2","tags" : ["旅游","玩游戲","渣男"]}},{"_index" : "cxf","_type" : "user","_id" : "1","_score" : 0.14181954,"_source" : {"name" : "張三","age" : 24,"desc" : "永遠的神","tags" : ["強","溫暖","博愛"]}}]} } 1.通過id查詢: GET /cxf/user/3 2.條件查詢: GET /cxf/user/_search?q=name:張三3.query查詢: GET /cxf/user/_search {"query": {"match": {"name": "張四" // 匹配屬性值}},"_source" : ["name", "age"] // 結果過濾, "sort": [ // 排序,排序之后分值就為null了{"age": {"order": "desc"}}],"from": 0, // 分頁,相當于limit。from是從第幾條開始,size是每頁多少條數據"size": 2 }4.多條件精確查詢: GET /cxf/user/_search {"query": {"bool": {"must": [ // 相當于mysql的and,所有的條件都要符合{"match": {"name": "張三"}},{"match": {"age": 24}}]}} }5.or操作: GET /cxf/user/_search {"query": {"bool": {"should": [ // 等價于or{"match": {"name": "張三"}},{"match": {"age": 25}}]}} }6.查詢不是 GET /cxf/user/_search {"query": {"bool": {"must_not": [ // 等價于!={"match": {"name": "三"}},{"match": {"age": 24}}]}} }7.過濾條件 GET /cxf/user/_search {"query": {"bool": {"must": [{"match": {"name": "張三"}}],"filter": {"range": {"age": {"gte": 10, // 查詢條件"lte": 24}}}}} } gt:大于 gte:大于等于 lt:小于 lte:小于等于8.匹配多個條件 多條件用空格隔開,只要滿足其中一個結果既可以被查出,這個時候可以通過分值進行判斷。 GET /cxf/user/_search {"query": {"match": {"tags": "男 游戲"}} }9.精確查詢 term查詢是直接通過倒排查詢進行精確查詢的。 term是直接查詢精確的值。 match會使用分詞器。(先分析文檔,然后再通過分析的文檔進行查詢!) text類型會被分詞解析,keyword是不會被分詞解析的! GET /cxf/user/_search {"query": {"term": {"name": {"value": "張四"}}} }10.高亮查詢 GET /cxf/user/_search {"query": {"match": {"name": "張三"}},"highlight": { // 搜索的高亮條件,會自動增加<em>張</em>標簽"pre_tags": "<p class='key' style='color:red'>", // 自定義高亮標簽"post_tags": "</p>","fields": {"name":{}}} }十、集成Springboot
1.pom
<dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId><version>7.6.0</version> </dependency>properties中需要指定es版本: <elasticsearch.version>7.6.0</elasticsearch.version><!--elasticsearch--> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency>2.配置
import org.apache.http.HttpHost; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestHighLevelClient; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;@Configuration public class ElasticsearchConfig {@Beanpublic RestHighLevelClient restHighLevelClient(){RestHighLevelClient restHighLevelClient = new RestHighLevelClient(RestClient.builder(new HttpHost("127.0.0.1", 9200, "http")));return restHighLevelClient;} }3.具體api
import com.alibaba.fastjson.JSON; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.bulk.BulkResponse; import org.elasticsearch.action.delete.DeleteRequest; import org.elasticsearch.action.delete.DeleteResponse; import org.elasticsearch.action.get.GetRequest; import org.elasticsearch.action.get.GetResponse; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.index.IndexResponse; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.support.master.AcknowledgedResponse; import org.elasticsearch.action.update.UpdateRequest; import org.elasticsearch.action.update.UpdateResponse; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.client.indices.CreateIndexRequest; import org.elasticsearch.client.indices.CreateIndexResponse; import org.elasticsearch.client.indices.GetIndexRequest; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.index.query.MatchQueryBuilder; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.search.fetch.subphase.FetchSourceContext; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import java.io.IOException; import java.util.ArrayList; import java.util.concurrent.TimeUnit;@RequestMapping("/es") @Controller public class ElasticsearchController {@Autowired@Qualifier("restHighLevelClient")private RestHighLevelClient client;/*** 索引*/@RequestMapping("/test1")public void test1() throws IOException {// 創建索引CreateIndexRequest indexCui = new CreateIndexRequest("cui");CreateIndexResponse resp = client.indices().create(indexCui, RequestOptions.DEFAULT);System.out.println(resp);// 判斷索引是否存在GetIndexRequest getIndexRequest = new GetIndexRequest("cui");boolean exists = client.indices().exists(getIndexRequest, RequestOptions.DEFAULT);System.out.println(exists);//刪除索引DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest("cui");AcknowledgedResponse delete = client.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);System.out.println(delete);}/*** POST添加數據*/@RequestMapping("/test2")public void test2() throws IOException {EsUser esUser = new EsUser();esUser.age =18;esUser.name = "張三";// 連接索引IndexRequest cui = new IndexRequest("cui");//規則 /cui/_doc/1cui.id("1");cui.timeout(TimeValue.timeValueSeconds(10));//cui.timeout("10s");// 請求體放進去cui.source(JSON.toJSONString(esUser), XContentType.JSON);//客戶端發送請求IndexResponse index = client.index(cui, RequestOptions.DEFAULT);System.out.println(index);// 第一次是created,以后再添加就是update了}/*** 文檔操作*/@RequestMapping("/test3")public void test3() throws IOException {/*** 判斷文檔是否存在*/GetRequest cui = new GetRequest("cui", "1");//不獲取返回的上下文(_source)cui.fetchSourceContext(new FetchSourceContext(false));cui.storedFields("_none_");boolean exists = client.exists(cui, RequestOptions.DEFAULT);System.out.println(exists);GetRequest idx = new GetRequest("cui", "1");GetResponse documentFields = client.get(idx, RequestOptions.DEFAULT);System.out.println(documentFields.getSourceAsString());// 打印文檔內容System.out.println(documentFields); // 返回的全部內容和命令是一樣的/*** 更新*/EsUser esUser = new EsUser();esUser.age =19;esUser.name = "張四";UpdateRequest cui1 = new UpdateRequest("cui", "1");cui1.timeout("1s");cui1.doc(JSON.toJSONString(esUser), XContentType.JSON);UpdateResponse update = client.update(cui1, RequestOptions.DEFAULT);System.out.println(update);/*** 刪除*/DeleteRequest cui2 = new DeleteRequest("cui", "1");cui2.timeout("1s");DeleteResponse delete = client.delete(cui2, RequestOptions.DEFAULT);System.out.println(delete);}/*** 批量操作*/@RequestMapping("/test4")public void test4() throws IOException {BulkRequest bulkRequest = new BulkRequest();bulkRequest.timeout("10s");ArrayList<EsUser> list = new ArrayList<>();list.add(new EsUser("崔1", 21));list.add(new EsUser("崔2", 22));list.add(new EsUser("崔3", 23));list.add(new EsUser("崔4", 24));list.add(new EsUser("崔5", 25));list.add(new EsUser("崔6", 26));list.add(new EsUser("崔7", 27));//批處理for (int i = 0; i < list.size(); i++) {// 批量修改刪除,對應修改即可bulkRequest.add(new IndexRequest("cui").id(i + 1 + "") // 不寫id會隨機生成id.source(JSON.toJSONString(list.get(i)), XContentType.JSON));}BulkResponse bulk = client.bulk(bulkRequest, RequestOptions.DEFAULT);System.out.println(bulk);}/*** 查詢* 就是對應基本的所有命令*/@RequestMapping("/test5")public void test5() throws IOException {SearchRequest searchRequest = new SearchRequest("cui");SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();//使用QueryBuilders,快速匹配查詢條件MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("name", "崔1");searchSourceBuilder.query(matchQueryBuilder).from(0)// 分頁.size(10).timeout(new TimeValue(10, TimeUnit.SECONDS));//searchSourceBuilder.highlighter();// 高亮searchRequest.source(searchSourceBuilder);// 把查詢條件放到searchRequestSearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);System.out.println(search.getHits());// 文檔內容System.out.println(search);for (SearchHit documentFields : search.getHits().getHits()) {System.out.println(documentFields.getSourceAsMap());// 遍歷}}}class EsUser{public String name;public Integer age;public EsUser(String name, Integer age) {this.name = name;this.age = age;}public EsUser() {} }十一、京東搜索
1.導入包
<!--解析網頁 jsoup ; tika包是解析視頻音樂的--> <dependency><groupId>org.jsoup</groupId><artifactId>jsoup</artifactId><version>1.10.2</version> </dependency>2.代碼
import org.jsoup.Connection; import org.jsoup.helper.HttpConnection; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements;import java.io.IOException; import java.net.URL; import java.util.ArrayList;public class HtmlParseUtils {public static void main(String[] args) throws IOException {ArrayList<Info> java = HtmlParseUtils.getInfo("java");for (Info info : java) {System.out.println(info);}}public static ArrayList<Info> getInfo(String info) throws IOException {// 獲取請求String url = "https://search.jd.com/Search?keyword=" + info;//解析網頁(解析返回的document就是瀏覽器的document對象)URL u = new URL(url);Connection con = HttpConnection.connect(url);con.timeout(300000);con.header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3861.400 QQBrowser/10.7.4313.400");con.header("cookie", "unpl=V2_ZzNtbURREEF3XxZReBAPVWIBRllKBUEQcw0VAyxOWVJhCkcIclRCFnUUR1BnGFUUZgoZWUNcQhFFCEdkeBBVAWMDE1VGZxBFLV0CFSNGF1wjU00zQwBBQHcJFF0uSgwDYgcaDhFTQEJ2XBVQL0oMDDdRFAhyZ0AVRQhHZH8ZXQBmBxteRmdzEkU4dl1yEV4DZTMTbUNnAUEpC0dSchtZSGMDE1hDU0oWcThHZHg%3d; __jdv=76161171|baidu-pinzhuan|t_288551095_baidupinzhuan|cpc|0f3d30c8dba7459bb52f2eb5eba8ac7d_0_77be3fa428ba43e59c3474bfff4f78dd|1620435006518; __jdu=510405825; areaId=13; ipLoc-djd=13-1007-37918-0; PCSYCityID=CN_370000_370200_370212; shshshfpa=b63cfa52-dd75-9d21-c820-0ae5f6a96ef1-1620435009; shshshfpb=abapWi%2F0i4o6AgQnM%2F5q%2F%2FQ%3D%3D; __jda=122270672.510405825.1620435006.1620435006.1620435007.1; __jdc=122270672; shshshfp=11c5062f56e8e6ad00ad498a9d3ab294; rkv=1.0; wlfstk_smdl=iycergr2qqxobmcam67n8ptxywbmufhd; qrsc=3; __jdb=122270672.8.510405825|1.1620435007; shshshsID=6e200de4a4e9605b03810b2ab647eb98_6_1620437334053; 3AB9D23F7A4B3C9B=RMWCKZRXMVHOY7FERSQDF7FV25CGZRNEEBLRZZLDHQWLBCLNY3I57D76RTH27WDER2KFJOAIHWKZJH7YDX7KREP5VA");Document document = con.get();//Document document = Jsoup.parse(u, 300000); // 京東這里會跳轉到登錄,咱們加上cookie// 所有js中能使用的方法,這里都能用Element j_goodsList = document.getElementById("J_goodsList");//獲取所有li標簽Elements li = j_goodsList.getElementsByTag("li");ArrayList<Info> list = new ArrayList<>();for (Element element : li) {String img = element.getElementsByTag("img").eq(0).attr("data-lazy-img");String price = element.getElementsByClass("p-price").eq(0).text();String name = element.getElementsByClass("p-name").eq(0).text();Info infos = new Info();infos.img = img;infos.name = name;infos.price = price;list.add(infos);}return list;} }class Info{String img;String price;String name;public String getImg() {return img;}public void setImg(String img) {this.img = img;}public String getPrice() {return price;}public void setPrice(String price) {this.price = price;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "Info{" +"img='" + img + '\'' +", price='" + price + '\'' +", name='" + name + '\'' +'}';} } import com.alibaba.fastjson.JSON; import org.apache.http.HttpHost; import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.bulk.BulkResponse; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.common.text.Text; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.index.query.MatchQueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder; import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit;public class EsTest {private static RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(new HttpHost("127.0.0.1", 9200, "http")));public static void main(String[] args) throws IOException {// insert();// 入庫// 查詢List<Map<String, Object>> java = searchPage("java", 0, 10);if(java.size() == 0){System.out.println("無數據");return;}for (Map<String, Object> stringObjectMap : java) {System.out.println(stringObjectMap);}}/*** 批量入庫* @throws IOException*/public static void insert() throws IOException {// 批量添加ArrayList<Info> list = HtmlParseUtils.getInfo("大數據");BulkRequest bulkRequest = new BulkRequest();bulkRequest.timeout("10s");//批處理for (int i = 0; i < list.size(); i++) {// 批量修改刪除,對應修改即可bulkRequest.add(new IndexRequest("jingdong")//.id(i + 1 + "") // 不寫id會隨機生成id.source(JSON.toJSONString(list.get(i)), XContentType.JSON));}BulkResponse bulk = client.bulk(bulkRequest, RequestOptions.DEFAULT);System.out.println(bulk);}public static List<Map<String, Object>> searchPage(String key, int pageNo, int pageSize) throws IOException {if(pageNo < 0){pageNo = 0;}SearchRequest searchRequest = new SearchRequest("jingdong");SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();//使用QueryBuilders,快速匹配查詢條件MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("name", key);searchSourceBuilder.query(matchQueryBuilder).from(pageNo)// 分頁.size(pageSize).timeout(new TimeValue(10, TimeUnit.SECONDS));//searchSourceBuilder.highlighter();// 高亮//高亮HighlightBuilder highlightBuilder = new HighlightBuilder();highlightBuilder.field("name").requireFieldMatch(false) //多個高亮顯示.preTags("<span style='color:red'>").postTags("</span>");searchSourceBuilder.highlighter(highlightBuilder);searchRequest.source(searchSourceBuilder);// 把查詢條件放到searchRequestSearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);//System.out.println(search.getHits());// 文檔內容//System.out.println(search);List<Map<String, Object>> list = new ArrayList<>();for (SearchHit documentFields : search.getHits().getHits()) {//System.out.println(documentFields.getSourceAsMap());// 遍歷Map<String, Object> sourceAsMap = documentFields.getSourceAsMap();// 原來的HighlightField name = documentFields.getHighlightFields().get("name"); // 獲取name高亮if(name != null){//替換高亮字段Text[] fragments = name.fragments();String newName = "";for (Text fragment : fragments) {newName += fragment;}sourceAsMap.put("name", newName);// 替換原來的name// 高亮之后,使用v-html解析即可}list.add(sourceAsMap);}return list;}}總結
以上是生活随笔為你收集整理的elasticSearch入门到java操作api一套搞定的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MySQL高级-索引是个什么东西?exp
- 下一篇: redis-数据类型与应用