RESTful 風(fēng)格寫法:
GET、POST、PUT、DELETE、HEAD。
JSON字符串:網(wǎng)絡(luò)中傳遞的字符串的格式符合JSON格式。
正排(正向)索引:
id | content |
---|---|
1001 | my name is zhang san |
1002 | i name is li si |
1003 | my name is wang wu |
倒排索引:
keyword | id |
---|---|
name | 1001,1002,1003 |
zhang | 1001a |
my | 1001,1003 |
創(chuàng)建索引
PUT請求:http://127.0.0.1:9200/索引名稱
返回值:
{ "acknowledged"【響應(yīng)結(jié)果】: true, # true 操作成功 //創(chuàng)建索引是否成功 "shards_acknowledged"【分片結(jié)果】: true, # 分片操作成功 "index"【索引名稱】: "shopping" //創(chuàng)建的索引名稱 } # 注意:創(chuàng)建索引庫的分片數(shù)默認(rèn) 1 片,在 7.0.0 之前的 Elasticsearch 版本中,默認(rèn) 5 片
表頭 | 含義 |
---|---|
health | 當(dāng)前服務(wù)器健康狀態(tài): green(集群完整) yellow(單點(diǎn)正常、集群不完整) red(單點(diǎn)不正常) |
status | 索引打開、關(guān)閉狀態(tài) |
index | 索引名 |
uuid | 索引統(tǒng)一編號 |
pri | 主分片數(shù)量 |
rep | 副本數(shù)量 |
docs.count | 可用文檔數(shù)量 |
docs.deleted | 文檔刪除狀態(tài)(邏輯刪除) |
store.size | 主分片和副分片整體占空間大小 |
pri.store.size | 主分片占空間大小 |
查看單個索引GET響應(yīng)返回結(jié)果 { "shopping"【索引名】: { "aliases"【別名】: {}, "mappings"【映射】: {}, "settings"【設(shè)置】: { "index"【設(shè)置 - 索引】: { "creation_date"【設(shè)置 - 索引 - 創(chuàng)建時間】: "1614265373911", "number_of_shards"【設(shè)置 - 索引 - 主分片數(shù)量】: "1", "number_of_replicas"【設(shè)置 - 索引 - 副分片數(shù)量】: "1", "uuid"【設(shè)置 - 索引 - 唯一標(biāo)識】: "eI5wemRERTumxGCc1bAk2A", "version"【設(shè)置 - 索引 - 版本】: { "created": "7080099" }, "provided_name"【設(shè)置 - 索引 - 名稱】: "shopping" } } } }
全部查詢:_search
單條數(shù)據(jù)查詢:_doc
全量更新:PUT
單屬性更新:POST
刪除數(shù)據(jù):DELETE
創(chuàng)建文檔:PUT響應(yīng)返回結(jié)果
創(chuàng)建文檔:PUT響應(yīng)返回結(jié)果 { "_index"【索引】: "shopping", "_type"【類型-文檔】: "_doc", "_id"【唯一標(biāo)識】: "Xhsa2ncBlvF_7lxyCE9G", #可以類比為 MySQL 中的主鍵,隨機(jī)生成 "_version"【版本】: 1, "result"【結(jié)果】: "created", #這里的 create 表示創(chuàng)建成功 "_shards"【分片】: { "total"【分片 - 總數(shù)】: 2, "successful"【分片 - 成功】: 1, "failed"【分片 - 失敗】: 0 }, "_seq_no": 0, "_primary_term": 1 }
查看文檔:GET響應(yīng)返回結(jié)果
查看文檔:GET響應(yīng)返回結(jié)果 { "_index"【索引】: "shopping", "_type"【文檔類型】: "_doc", "_id": "1", "_version": 2, "_seq_no": 2, "_primary_term": 2, "found"【查詢結(jié)果】: true, # true 表示查找到,false 表示未查找到 "_source"【文檔源信息】: { "title": "華為手機(jī)", "category": "華為", "images": "http://www.gulixueyuan.com/hw.jpg", "price": 4999.00 } }
多條件查詢寫法:
多條件查詢寫法: { ? "query":{//表示查詢 ? "match":{//部分匹配(match_all//全量查詢,match_phrase//全匹配) ? "條件key":"條件value" ? } ? }, ? "from":0,//起始位置(頁碼-1*每頁數(shù)據(jù)條數(shù)) ? "size":2,//每頁查詢條數(shù) ? "_soource":{ ? "title"http://想要查詢出來的字段 ? }, ? "sort":{ ? "price":{//需要排序字段 ? "order":"asc"http://desc 排序方式 ? } ? } } { ? "query":{ ? "bool":{//條件參數(shù) ? "must":[//多個條件同時成立 ? should滿足一個條件即成立 ? { ? "match":{ ? "條件key":"條件value" ? } ? }, ? { ? "match":{ ? "條件key":"條件value" ? } ? } ? ], ? "filter":{//過濾 ? "range":{//范圍 ? "price":{//條件 ? "gt":5000//大于 ? } ? } ? } ? } ? }, ? "highlight":{//高亮 ? ? "pre_tags": "<font color='red'>", ? "post_tags": "</font>", ? "fields":{//字段 ? "高亮字段" : {} ? } ? } } { ? "aggs":{//聚合操作 ? "price_group":{//名稱,隨意起名 (price_avg:平均值) ? "terms":{//分組 (avg:平均值) ? "分組字段" : "price" //分組字段 ? } ? } ? }, ? "size":0 //表示不需要原始數(shù)據(jù) }
PUT添加映射關(guān)系 GET獲取數(shù)據(jù)
PUT添加映射關(guān)系 GET獲取數(shù)據(jù) { ? ?"properties":{//映射 ? ? ? ?"name":{ ? ? ? ? ? ?"type" : "text",//查詢不需要完全匹配 ? ? ? ? ? ?"index" : true//是否能被索引,是否能被查詢 ? ? ? }, ? ? ? ?"sex":{ ? ? ? ? ? ?"type" : "keyword",//查詢需要完全匹配(不能被分詞) ? ? ? ? ? ?"index" : true ? ? ? }, ? ? ? ?"tel":{ ? ? ? ? ? ?"type" : "keyword", ? ? ? ? ? ?"index" : false ? ? ? } ? } }
Java中的使用
在Maven項(xiàng)目中的pom文件下引入依賴
在Maven項(xiàng)目中的pom文件下引入依賴 <dependencies> <dependency> <groupId>org.elasticsearch</groupId> <artifactId>elasticsearch</artifactId> <version>7.8.0</version> </dependency> <!-- elasticsearch 的客戶端 --> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-high-level-client</artifactId> <version>7.8.0</version> </dependency> <!-- elasticsearch 依賴 2.x 的 log4j --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.8.2</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.8.2</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.9</version> </dependency> <!-- junit 單元測試 --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> </dependencies>
ES索引在java里簡單操作:
? ?/* ? ? ? ?ES索引在java里簡單操作: ? ?*/ //創(chuàng)建ES客戶端 RestHighLevelClient esClent = new RestHighLevelClient( ? RestClient.builder(new HttpHost("localhost",9200,"http")) ? ); //創(chuàng)建索引 CreateIndexResponse createIndexResponse = esClient.indices().create(new CreateIndexRequst("索引名稱"),RequestOptions.DEFAULT); //響應(yīng)狀態(tài) boolean acknowledged = createIndexResponse.isAcknowledged(); //查詢索引 GetIndexResponse getIndexResponse = esClent.indices().get(new GetIndexRequest("索引名"),RequestOptions.DEFAULT); getIndexResponse.getAliases();//別名 ? ?getIndexResponse.getMappings();//配置 機(jī)構(gòu) ? ?getIndexResponse.getSettings();// //刪除索引 DeleteIndexResponse deleteIndexResponse = esClent.indices().delete(new DeleteIndexRequest("索引名"),RequestOptions.DEFAULT); deleteIndexResponse.isAcknowledged();//響應(yīng)狀態(tài) //關(guān)閉ES客戶端 esClent.close();
ES數(shù)據(jù)在java里簡單操作:
/* ? ? ? ?ES數(shù)據(jù)在java里簡單操作: */ //創(chuàng)建ES客戶端 RestHighLevelClient esClient = new RestHighLevelClient( ? RestClient.builder(new HttpHost("localhost",9200,"http")) ? ); //插入數(shù)據(jù) ? Map map = new Map(); map.put("name","zhangsan"); map.put("sex","男"); map.put("tel","15234456234"); //向ES插入數(shù)據(jù),必須將數(shù)據(jù)轉(zhuǎn)換為JSON格式 IndexRequest indexRequest = new IndexRequest.index("索引名").id("id"); ObjectMapper mapper = new ObjectMapper(); String userJson = mapper.writeValueAsString(map); indexRequest.source(userJson,XContentType.JSON); IndexResponse indexResponse = esClient.index(indexRequest,RequestOptions.DEFAULT); indexResponse.getResult();//插入響應(yīng)狀態(tài)(CREATED:插入成功) //修改數(shù)據(jù) UpdateRequest updateRequest = new UpdateRequest().index("索引名").id("id"); updateRequest.doc(XContentType.JSON,"sex","女"); ? ?UpdateResponse updateResponse = esClient.update(updateRequest,RequestOptions.DEFAULT); ? ? updateResponse.getResult();//修改響應(yīng)狀態(tài)(CREATED:修改成功) //查詢數(shù)據(jù) GetREquest getRequest = new GetRequest().index("索引名").id("id"); GetResponse getResponse = esClient.get(getRequest,RequestOptions.DEEFAULT); getResponse.getSouceAsString(); //刪除數(shù)據(jù) DeleteRequest deleteRequest = new DeleteRequest().index("索引名").id("id"); DeleteResponse deleteResponse = esClient.delete(deleteRequest,RequestOptions.DEFAULT); //關(guān)閉ES客戶端 esClient.close();
ES數(shù)據(jù)在java里批量操作:
/* ES數(shù)據(jù)在java里批量操作: */ //創(chuàng)建ES客戶端 RestHighLevelClient esClient = new RestHighLevelClient( ? RestClient.builder(new HttpHost("localhost",9200,"http")) ? ); //批量插入數(shù)據(jù) BulkRequest bulkRequest = new BulkRequest(); bulkRequest.add(new IndexRequest.index("索引名").id("1001").source(XContentType.JSON,"name","zhangsan")); bulkRequest.add(new IndexRequest.index("索引名").id("1002").source(XContentType.JSON,"name","lisi")); BulkResponse bulkResponse = esClient.bulk(bulkRequest,RequestOptions.DEFAULT); bulkResponse.getTook(); bulkResponse.getItems(); //批量刪除數(shù)據(jù) bulkRequest.add(new DeleteRequest.index("索引名").id("1001")); bulkRequest.add(new DeleteRequest.index("索引名").id("1002")); BulkResponse bulkResponse = esClient.bulk(bulkRequest,RequestOptions.DEFAULT); bulkResponse.getTook(); bulkResponse.getItems(); //關(guān)閉ES客戶端 esClient.colse();
Java里操作ES數(shù)據(jù)的使用
/* Java里操作ES數(shù)據(jù)的使用 */ //創(chuàng)建ES客戶端 RestHighLevelClient esClient = new RestHighLevelClient( ? RestClient.builder(new HttpHost("localhost",9200,"http")) ? ); //查詢索引中全部的數(shù)據(jù) matchAllQuery SearchRequest searchRequest = new SearchRequest().indices("索引名"); searchRequest.source(new SearchSourecBuilder().query(QueryBuilders.matchAllQuery())); SearchResponse searchResponse = esClient.search(searchRequest,RequestOptions.DEFAULT); SearchHits hits = searchResponse.getHits(); hits.getTotalHits(); searchResponse.getTook(); //條件查詢 termQuery SearchRequest searchRequest = new SearchRequest().indices("索引名"); searchRequest.source(new SearchSourceBuilder().query(QueryBuilders.termQuery("age",30))); SearchResponse searchResponse = esClient.search(searchRequest,RequestOptions.DEFAULT); SearchHits searchHits = searchResponse.getHits(); hits.getTotalHits(); searchResponse.getTook(); //分頁 排序 過濾字段 查詢 SearchRequest searchRequest = new SearchRequest().indices("索引名"); SearchSourceBuilder builder = new SearchSourceBuilder().query(QueryBuilder.matchAllQuery()); ---------------------------------------------------------------- // (當(dāng)前頁碼-1)*每頁顯示條數(shù) builder.from(0);//分頁用 builder.size(2);//分頁用 ---------------------------------------------------------------- builder.sort("排序字段",SortOrder.DESC);//排序用 ---------------------------------------------------------------- String[] excludes = {};//排除的內(nèi)容 String[] includes = {"name"};//包含的內(nèi)容 builder.fetchSource(includes,excludes);//過濾字段查詢 ---------------------------------------------------------------- searchRequest.source(builder); SearchResponse searchResponse = esClient.search(searchRequest,RequestOptions.DEFAULT); SearchHits searchHits = searchResponse.getHits(); hits.getTotalHits(); searchResponse.getTook(); //組合查詢 SearchRequest searchRequest = new SearchRequest().indices("索引名"); SearchSourceBuilder builder = new SearchSourceBuilder(); BoolQueryBuilder boolQueryBuilder = QueryBuilder.boolQuery(); boolQueryBuilder.must(QueryBuilder.matchQuery("age",30));//滿足這個條件 boolQueryBuilder.mustNot(QueryBuilder.matchQuery("sex","男"));//不滿足這個條件 --------------------------滿足30或者滿足40------------------------------------ boolQueryBuilder.should(QueryBuilder.matchQuery("age",30)); boolQueryBuilder.should(QueryBuilder.matchQuery("age",40)); searchRequest.source(builder.query(boolQueryBuilder)); ----------------------------------------------------------------------------- ? //范圍查詢 ? ?RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("age"); rangerQuery.get(30);//>= rangerQuery.lte(40);//<= searchRequest.source(builder.query(rangerQuery)); ----------------------------------------------------------------------------- ? ?//模糊查詢 ? ?searchRequest.source(builder.query( QueryBuilder.fuzzyQuery("name","wangwu").fuzziness(Fuzziness.ONE))); ----------------------------------------------------------------------------- ? ?//高亮查詢 ? ?TermsQueryBuilder termQueryBuilder = QueryBuilder.termsQuery("name","wangwu"); HighlightBuilder highlightBuilder = new HighlightBuilder(); highlightBuilder.preTags("<font color='red' >");//添加前綴 highlightBuilder.postTags("</font>");//添加后綴 highlightBuilder.field("name");//高亮標(biāo)簽內(nèi)容 builder.highter(highlightBuilder); builder.query(termQueryBuilder); searchRequest.source(builder); ----------------------------------------------------------------------------- ? ?//聚合查詢 ? ?AggregationBuilder aggregationBuilder = AggregationBuilders.max("maxAge").field("age"); ? ?builder.aggregation(aggregationBuilder); ? ?searchRequest.source(builder); ---------------------------------------------------------------------------- ? ?//分組查詢 ? ?AggregationBuilder aggregationBuilder = AggregationBuilders.terms("ageGroup").field("age"); builder.aggregation(aggregationBuilder); ? ?searchRequest.source(builder); --------------------------------------------------------------------------- ? ?SearchResponse searchResponse = esClient.search(searchRequest,RequestOptions.DEFAULT); SearchHits searchHits = searchResponse.getHits(); hits.getTotalHits(); searchResponse.getTook(); //關(guān)閉ES客戶端 esClient.close();
ES環(huán)境
單機(jī):
集群:
????????一個集群就是由一個或者多個服務(wù)器節(jié)點(diǎn)組織在一起的,共通持有整個的數(shù)據(jù),并一起提供索引和搜索功能。一個Elasticsearch集群有一個唯一的名字標(biāo)識,這個名字默認(rèn)就是“elasticsearch”。這個名字是重要的,因?yàn)橐粋€節(jié)點(diǎn)只能通過指定某個集群的名字,來加入這個集群。
節(jié)點(diǎn)Node:
????????集群中包含很多服務(wù)器,一個節(jié)點(diǎn)就是其中的一個服務(wù)器。作為集群的一部分,它存儲數(shù)據(jù),參與集群的索引和搜索功能。(注:一個節(jié)點(diǎn)就是一個服務(wù)器不絕對)
集群節(jié)點(diǎn)配置
#節(jié)點(diǎn) 1 的配置信息: #集群名稱,節(jié)點(diǎn)之間要保持一致 cluster.name: my-elasticsearch #節(jié)點(diǎn)名稱,集群內(nèi)要唯一 node.name: node-1001 node.master: true node.data: true #ip 地址 network.host: localhost #http 端口 http.port: 1001 #tcp 監(jiān)聽端口 transport.tcp.port: 9301 #discovery.seed_hosts: ["localhost:9301", "localhost:9302","localhost:9303"] #discovery.zen.fd.ping_timeout: 1m #discovery.zen.fd.ping_retries: 5 #集群內(nèi)的可以被選為主節(jié)點(diǎn)的節(jié)點(diǎn)列表 #cluster.initial_master_nodes: ["node-1", "node-2","node-3"] #跨域配置 #action.destructive_requires_name: true http.cors.enabled: true http.cors.allow-origin: "*"
集群狀態(tài)查詢:
http://ip地址:端口號/_cluster/health
Elasticsearch 進(jìn)階
索引(Index)
Elasticsearch索引的精髓:一切設(shè)計(jì)都是為了提高搜素的性能。
類型(Type)
5.x支持多種type 6.x只能有一種type 7.x不在支持自定義索引類型(默認(rèn)類型為:_doc)
文檔(Document)
一個文檔是一個可被索引的基礎(chǔ)信息單元,也就是一條數(shù)據(jù)(以JSON格式表示)
字段(Filed)
相當(dāng)于是數(shù)據(jù)表的字段,對文檔數(shù)據(jù)根據(jù)不同屬性進(jìn)行的分類標(biāo)識
映射(Mapping)
是處理數(shù)據(jù)的方式和規(guī)則方面的一些限制。
分片(Shards)
分片很重要,主要有兩方面的原因:
1、允許你水平分割/擴(kuò)展你的內(nèi)容容量。
2、允許你在分片之上進(jìn)行分布式的、并行的操作,進(jìn)而提高性能/吞吐量。
副本(Replicas)
復(fù)制分片之所以重要,主要有兩個原因:
1、在分片/節(jié)點(diǎn)失敗的情況下,提供了高可用性。因?yàn)檫@個原因,注意到復(fù)制分片從不與原/主要(original/primary)分片置于同一節(jié)點(diǎn)是非常重要的。
2、擴(kuò)展你的搜索量/吞吐量,因?yàn)樗阉乜梢栽谒械母北旧喜⑿羞M(jìn)行。
分配(Allocation)
將分片分配給某個節(jié)點(diǎn)的過程,包括分配主分片或者副本。
分布式集群
單節(jié)點(diǎn)集群
單節(jié)點(diǎn)情況下分片正常啟用,副本不進(jìn)行分配
SpringData
pom文件引入依賴
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="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> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.6.RELEASE</version> <relativePath/> </parent> <groupId>com.atguigu.es</groupId> <artifactId>springdata-elasticsearch</artifactId> <version>1.0</version> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-test</artifactId> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> </dependency> </dependencies> </project>
增加配置文件
# es 服務(wù)地址 elasticsearch.host=127.0.0.1 # es 服務(wù)端口 elasticsearch.port=9200 # 配置日志級別,開啟 debug 日志 logging.level.com.atguigu.es=debug
Elasticsearch優(yōu)化
硬件選擇
Elasticsearch 的基礎(chǔ)是 Lucene,所有的索引和文檔數(shù)據(jù)是存儲在本地的磁盤中,具體的路徑可在 ES 的配置文件../config/elasticsearch.yml 中配置,如下: # Path to directory where to store the data (separate multiple locations by comma): #path.data: /path/to/data # Path to log files: #path.logs: /path/to/logs 磁盤在現(xiàn)代服務(wù)器上通常都是瓶頸。Elasticsearch 重度使用磁盤,你的磁盤能處理的吞吐量 越大,你的節(jié)點(diǎn)就越穩(wěn)定。這里有一些優(yōu)化磁盤 I/O 的技巧: ? 使用 SSD。就像其他地方提過的, 他們比機(jī)械磁盤優(yōu)秀多了。 ? 使用 RAID 0。條帶化 RAID 會提高磁盤 I/O,代價顯然就是當(dāng)一塊硬盤故障時整個就故障了。不要 使用鏡像或者奇偶校驗(yàn) RAID 因?yàn)楦北疽呀?jīng)提供了這個功能。 ? 另外,使用多塊硬盤,并允許 Elasticsearch 通過多個 path.data 目錄配置把數(shù)據(jù)條帶化分配到它們上 面。 ? 不要使用遠(yuǎn)程掛載的存儲,比如 NFS 或者 SMB/CIFS。這個引入的延遲對性能來說完全是背道而馳 的。
分片策略
合理設(shè)置分片數(shù)
分片和副本的設(shè)計(jì)為 ES 提供了支持分布式和故障轉(zhuǎn)移的特性,但并不意味著分片和副本是可以無限分配的。而且索引的分片完成分配后由于索引的路由機(jī)制,我們是不能重新修改分片數(shù)的。 可能有人會說,我不知道這個索引將來會變得多大,并且過后我也不能更改索引的大小,所以為了保險起見,還是給它設(shè)為 1000 個分片吧。但是需要知道的是,一個分片并不是沒有代價的。需要了解: ? 一個分片的底層即為一個 Lucene 索引,會消耗一定文件句柄、內(nèi)存、以及 CPU 運(yùn)轉(zhuǎn)。 ? 每一個搜索請求都需要命中索引中的每一個分片,如果每一個分片都處于不同的節(jié)點(diǎn)還好, 但如果多個分片都需要在同一個節(jié)點(diǎn)上競爭使用相同的資源就有些糟糕了。 ? 用于計(jì)算相關(guān)度的詞項(xiàng)統(tǒng)計(jì)信息是基于分片的。如果有許多分片,每一個都只有很少的數(shù)據(jù)會導(dǎo)致很低的相關(guān)度。 一個業(yè)務(wù)索引具體需要分配多少分片可能需要架構(gòu)師和技術(shù)人員對業(yè)務(wù)的增長有個預(yù)先的判斷,橫向擴(kuò)展應(yīng)當(dāng)分階段進(jìn)行。為下一階段準(zhǔn)備好足夠的資源。 只有當(dāng)你進(jìn)入到下一個階段,你才有時間思考需要作出哪些改變來達(dá)到這個階段。一般來說,我們遵循一些原則: ? 控制每個分片占用的硬盤容量不超過 ES 的最大 JVM 的堆空間設(shè)置(一般設(shè)置不超過 32G,參考下文的 JVM 設(shè)置原則),因此,如果索引的總?cè)萘吭?500G 左右,那分片大小在 16 個左右即可;當(dāng)然,最好同時考慮原則 2。 ? 考慮一下 node 數(shù)量,一般一個節(jié)點(diǎn)有時候就是一臺物理機(jī),如果分片數(shù)過多,大大超過了節(jié)點(diǎn)數(shù),很可能會導(dǎo)致一個節(jié)點(diǎn)上存在多個分片,一旦該節(jié)點(diǎn)故障,即使保持了 1 個以上的副本,同樣有可能會導(dǎo)致數(shù)據(jù)丟失,集群無法恢復(fù)。所以, 一般都設(shè)置分片數(shù)不超過節(jié)點(diǎn)數(shù)的 3 倍。 ? 主分片,副本和節(jié)點(diǎn)最大數(shù)之間數(shù)量,我們分配的時候可以參考以下關(guān)系:節(jié)點(diǎn)數(shù)<=主分片數(shù)*(副本數(shù)+1)
推遲分片分配
對于節(jié)點(diǎn)瞬時中斷的問題,默認(rèn)情況,集群會等待一分鐘來查看節(jié)點(diǎn)是否會重新加入,如果這個節(jié)點(diǎn)在此期間重新加入,重新加入的節(jié)點(diǎn)會保持其現(xiàn)有的分片數(shù)據(jù),不會觸發(fā)新的分片分配。這樣就可以減少 ES 在自動再平衡可用分片時所帶來的極大開銷。 通過修改參數(shù) delayed_timeout ,可以延長再均衡的時間,可以全局設(shè)置也可以在索引級別進(jìn)行修改: PUT /_all/_settings { "settings": { "index.unassigned.node_left.delayed_timeout": "5m" } }
路由選擇
當(dāng)我們查詢文檔的時候,Elasticsearch 如何知道一個文檔應(yīng)該存放到哪個分片中呢?它其實(shí)是通過下面這個公式來計(jì)算出來: shard = hash(routing) % number_of_primary_shards routing 默認(rèn)值是文檔的 id,也可以采用自定義值,比如用戶 id。 ? 不帶 routing 查詢 在查詢的時候因?yàn)椴恢酪樵兊臄?shù)據(jù)具體在哪個分片上,所以整個過程分為 2 個步驟 ? 分發(fā):請求到達(dá)協(xié)調(diào)節(jié)點(diǎn)后,協(xié)調(diào)節(jié)點(diǎn)將查詢請求分發(fā)到每個分片上。 ? 聚合: 協(xié)調(diào)節(jié)點(diǎn)搜集到每個分片上查詢結(jié)果,在將查詢的結(jié)果進(jìn)行排序,之后給用戶返回結(jié)果。 ? 帶 routing 查詢 查詢的時候,可以直接根據(jù) routing 信息定位到某個分配查詢,不需要查詢所有的分配,經(jīng)過協(xié)調(diào)節(jié)點(diǎn)排序。 向上面自定義的用戶查詢,如果 routing 設(shè)置為 userid 的話,就可以直接查詢出數(shù)據(jù)來,效率提升很多。
寫入速度優(yōu)化
ES 的默認(rèn)配置,是綜合了數(shù)據(jù)可靠性、寫入速度、搜索實(shí)時性等因素。實(shí)際使用時,我們需要根據(jù)公司要求,進(jìn)行偏向性的優(yōu)化。 針對于搜索性能要求不高,但是對寫入要求較高的場景,我們需要盡可能的選擇恰當(dāng)寫優(yōu)化策略。綜合來說,可以考慮以下幾個方面來提升寫索引的性能: ? 加大 Translog Flush ,目的是降低 Iops、Writeblock。 ? 增加 Index Refresh 間隔,目的是減少 Segment Merge 的次數(shù)。 ? 調(diào)整 Bulk 線程池和隊(duì)列。 ? 優(yōu)化節(jié)點(diǎn)間的任務(wù)分布。 ? 優(yōu)化 Lucene 層的索引建立,目的是降低 CPU 及 IO。
批量數(shù)據(jù)提交
ES 提供了 Bulk API 支持批量操作,當(dāng)我們有大量的寫任務(wù)時,可以使用 Bulk 來進(jìn) 行批量寫入。 通用的策略如下:Bulk 默認(rèn)設(shè)置批量提交的數(shù)據(jù)量不能超過 100M。數(shù)據(jù)條數(shù)一般是 根據(jù)文檔的大小和服務(wù)器性能而定的,但是單次批處理的數(shù)據(jù)大小應(yīng)從 5MB~15MB 逐漸 增加,當(dāng)性能沒有提升時,把這個數(shù)據(jù)量作為最大值。
優(yōu)化存儲設(shè)備
ES 是一種密集使用磁盤的應(yīng)用,在段合并的時候會頻繁操作磁盤,所以對磁盤要求較高,當(dāng)磁盤速度提升之后,集群的整體性能會大幅度提高。
合理使用合并
Lucene 以段的形式存儲數(shù)據(jù)。當(dāng)有新的數(shù)據(jù)寫入索引時,Lucene 就會自動創(chuàng)建一個新的段。 隨著數(shù)據(jù)量的變化,段的數(shù)量會越來越多,消耗的多文件句柄數(shù)及 CPU 就越多,查詢效率就會下降。 由于 Lucene 段合并的計(jì)算量龐大,會消耗大量的 I/O,所以 ES 默認(rèn)采用較保守的策 略,讓后臺定期進(jìn)行段合并
減少Refresh的次數(shù)
Lucene 在新增數(shù)據(jù)時,采用了延遲寫入的策略,默認(rèn)情況下索引的 refresh_interval 為1 秒。 Lucene 將待寫入的數(shù)據(jù)先寫到內(nèi)存中,超過 1 秒(默認(rèn))時就會觸發(fā)一次 Refresh, 然后 Refresh 會把內(nèi)存中的的數(shù)據(jù)刷新到操作系統(tǒng)的文件緩存系統(tǒng)中。 如果我們對搜索的實(shí)效性要求不高,可以將 Refresh 周期延長,例如 30 秒。 這樣還可以有效地減少段刷新次數(shù),但這同時意味著需要消耗更多的 Heap 內(nèi)存。
加大Flush設(shè)置
Flush 的主要目的是把文件緩存系統(tǒng)中的段持久化到硬盤,當(dāng) Translog 的數(shù)據(jù)量達(dá)到512MB 或者 30 分鐘時,會觸發(fā)一次 Flush。 index.translog.flush_threshold_size 參數(shù)的默認(rèn)值是 512MB,我們進(jìn)行修改。增加參數(shù)值意味著文件緩存系統(tǒng)中可能需要存儲更多的數(shù)據(jù),所以我們需要為操作系統(tǒng) 的文件緩存系統(tǒng)留下足夠的空間。
減少副本的數(shù)量
ES 為了保證集群的可用性,提供了 Replicas(副本)支持,然而每個副本也會執(zhí)行分 析、索引及可能的合并過程,所以 Replicas 的數(shù)量會嚴(yán)重影響寫索引的效率。 當(dāng)寫索引時,需要把寫入的數(shù)據(jù)都同步到副本節(jié)點(diǎn),副本節(jié)點(diǎn)越多,寫索引的效率就越 慢。 如 果 我 們 需 要 大 批 量 進(jìn) 行 寫 入 操 作 , 可 以 先 禁 止 Replica 復(fù) 制 , 設(shè) 置 index.number_of_replicas: 0 關(guān)閉副本。在寫入完成后,Replica 修改回正常的狀態(tài)。
內(nèi)存設(shè)置
ES 默認(rèn)安裝后設(shè)置的內(nèi)存是 1GB,對于任何一個現(xiàn)實(shí)業(yè)務(wù)來說,這個設(shè)置都太小了。 如果是通過解壓安裝的 ES,則在 ES 安裝文件中包含一個 jvm.option 文件,添加如下命令來設(shè)置 ES 的堆大小,Xms 表示堆的初始大小,Xmx 表示可分配的最大內(nèi)存,都是 1GB。 確保 Xmx 和 Xms 的大小是相同的,其目的是為了能夠在 Java 垃圾回收機(jī)制清理完堆區(qū)后不需要重新分隔計(jì)算堆區(qū)的大小而浪費(fèi)資源,可以減輕伸縮堆大小帶來的壓力。 假設(shè)你有一個 64G 內(nèi)存的機(jī)器,按照正常思維思考,你可能會認(rèn)為把 64G 內(nèi)存都給ES 比較好,但現(xiàn)實(shí)是這樣嗎, 越大越好?雖然內(nèi)存對 ES 來說是非常重要的,但是答案是否定的! 因?yàn)?ES 堆內(nèi)存的分配需要滿足以下兩個原則: ? 不要超過物理內(nèi)存的 50%:Lucene 的設(shè)計(jì)目的是把底層 OS 里的數(shù)據(jù)緩存到內(nèi)存中。 Lucene 的段是分別存儲到單個文件中的,這些文件都是不會變化的,所以很利于緩存,同時操作系 統(tǒng)也會把這些段文件緩存起來,以便更快的訪問。 如果我們設(shè)置的堆內(nèi)存過大,Lucene 可用的內(nèi)存將會減少,就會嚴(yán)重影響降低 Lucene 的全文本查詢性能。 ? 堆內(nèi)存的大小最好不要超過 32GB:在 Java 中,所有對象都分配在堆上,然后有一個 Klass Pointer 指 針指向它的類元數(shù)據(jù)。 這個指針在 64 位的操作系統(tǒng)上為 64 位,64 位的操作系統(tǒng)可以使用更多的內(nèi)存(2^64)。在 32 位的系統(tǒng)上為 32 位,32 位的操作系統(tǒng)的最大尋址空間為 4GB(2^32)。 但是 64 位的指針意味著更大的浪費(fèi),因?yàn)槟愕闹羔槺旧泶罅?。浪費(fèi)內(nèi)存不算,更糟糕的是,更大的 指針在主內(nèi)存和緩存器(例如 LLC, L1 等)之間移動數(shù)據(jù)的時候,會占用更多的帶寬。 最終我們都會采用 31 G 設(shè)置 -Xms 31g -Xmx 31g 假設(shè)你有個機(jī)器有 128 GB 的內(nèi)存,你可以創(chuàng)建兩個節(jié)點(diǎn),每個節(jié)點(diǎn)內(nèi)存分配不超過 32 GB。 也就是說 不超過 64 GB 內(nèi)存給 ES 的堆內(nèi)存,剩下的超過 64 GB 的內(nèi)存給 Lucene
重要配置
參數(shù)名 | 參數(shù)值 | 說明 |
---|---|---|
cluster.name | elasticsearch | 配置 ES 的集群名稱,默認(rèn)值是 ES,建議改成與所存數(shù)據(jù)相關(guān)的名稱,ES 會自動發(fā)現(xiàn)在同一網(wǎng)段下的 集群名稱相同的節(jié)點(diǎn) |
node.name | node-1 | 集群中的節(jié)點(diǎn)名,在同一個集群中不能重復(fù)。節(jié)點(diǎn)的名稱一旦設(shè)置,就不能再改變了。當(dāng)然,也可以設(shè) 置 成 服 務(wù) 器 的 主 機(jī) 名 稱 , 例 如node.name:${HOSTNAME}。 |
node.master | true | 指定該節(jié)點(diǎn)是否有資格被選舉成為 Master 節(jié)點(diǎn),默認(rèn)是 True,如果被設(shè)置為 True,則只是有資格成為Master 節(jié)點(diǎn),具體能否成為 Master 節(jié)點(diǎn),需要通過選舉產(chǎn)生。 |
node.data | true | 指定該節(jié)點(diǎn)是否存儲索引數(shù)據(jù),默認(rèn)為 True。數(shù)據(jù)的增、刪、改、查都是在 Data 節(jié)點(diǎn)完成的。 |
index.number_of_shards | 1 | 設(shè)置都索引分片個數(shù),默認(rèn)是 1 片。也可以在創(chuàng)建索引時設(shè)置該值,具體設(shè)置為多大都值要根據(jù)數(shù)據(jù)量的大小來定。如果數(shù)據(jù)量不大,則設(shè)置成 1 時效率最高 |
index.number_of_replicas | 1 | 設(shè)置默認(rèn)的索引副本個數(shù),默認(rèn)為 1 個。副本數(shù)越多,集群的可用性越好,但是寫索引時需要同步的數(shù)據(jù)越多。 |
transport.tcp.compress | true | 設(shè)置在節(jié)點(diǎn)間傳輸數(shù)據(jù)時是否壓縮,默認(rèn)為 False,不壓縮 |
discovery.zen.minimum_master_nodes | 1 | 設(shè)置在選舉 Master 節(jié)點(diǎn)時需要參與的最少的候選主節(jié)點(diǎn)數(shù),默認(rèn)為 1。如果使用默認(rèn)值,則當(dāng)網(wǎng)絡(luò)不穩(wěn)定時有可能會出現(xiàn)腦裂。 合理的數(shù)值為 (master_eligible_nodes/2)+1 ,其中master_eligible_nodes 表示集群中的候選主節(jié)點(diǎn)數(shù) |
discovery.zen.ping.timeout | 3s | 設(shè)置在集群中自動發(fā)現(xiàn)其他節(jié)點(diǎn)時 Ping 連接的超時時間,默認(rèn)為 3 秒。 在較差的網(wǎng)絡(luò)環(huán)境下需要設(shè)置得大一點(diǎn),防止因誤判該節(jié)點(diǎn)的存活狀態(tài)而導(dǎo)致分片的轉(zhuǎn)移 |
Elasticsearch面試題整理
為什么要使用 Elasticsearch?
系統(tǒng)中的數(shù)據(jù),隨著業(yè)務(wù)的發(fā)展,時間的推移,將會非常多,而業(yè)務(wù)中往往采用模糊查詢進(jìn)行數(shù)據(jù)的搜索,而模糊查詢會導(dǎo)致查詢引擎放棄索引,導(dǎo)致系統(tǒng)查詢數(shù)據(jù)時都是全表掃描,在百萬級別的數(shù)據(jù)庫中,查詢效率是非常低下的,而我們使用 ES 做一個全文索引,將經(jīng)常查詢的系統(tǒng)功能的某些字段,比如說電商系統(tǒng)的商品表中商品名,描述、價格還有 id 這些字段我們放入 ES 索引庫里,可以提高查詢速度。
Elasticsearch 的 master 選舉流程?
? Elasticsearch 的選主是 ZenDiscovery 模塊負(fù)責(zé)的,主要包含 Ping(節(jié)點(diǎn)之間通過這個 RPC 來發(fā)現(xiàn)彼此)和 Unicast(單播模塊包含一個主機(jī)列表以控制哪些節(jié)點(diǎn)需要 ping 通)這兩部分 ? 對所有可以成為 master 的節(jié)點(diǎn)(node.master: true)根據(jù) nodeId 字典排序,每次選舉每個節(jié)點(diǎn)都把自己所知道節(jié)點(diǎn)排一次序,然后選出第一個(第 0 位)節(jié)點(diǎn),暫且認(rèn)為它是 master 節(jié)點(diǎn)。 ? 如果對某個節(jié)點(diǎn)的投票數(shù)達(dá)到一定的值(可以成為 master 節(jié)點(diǎn)數(shù) n/2+1)并且該節(jié)點(diǎn)自己也選舉自己,那這個節(jié)點(diǎn)就是 master。否則重新選舉一直到滿足上述條件。 ? master 節(jié)點(diǎn)的職責(zé)主要包括集群、節(jié)點(diǎn)和索引的管理,不負(fù)責(zé)文檔級別的管理;data 節(jié)點(diǎn)可以關(guān)閉 http功能。
Elasticsearch 集群腦裂問題?
“腦裂”問題可能的成因: ? 網(wǎng)絡(luò)問題:集群間的網(wǎng)絡(luò)延遲導(dǎo)致一些節(jié)點(diǎn)訪問不到 master,認(rèn)為 master 掛掉了從而選舉出新的master,并對 master 上的分片和副本標(biāo)紅,分配新的主分片 ? 節(jié)點(diǎn)負(fù)載:主節(jié)點(diǎn)的角色既為 master 又為 data,訪問量較大時可能會導(dǎo)致 ES 停止響應(yīng)造成大面積延遲,此時其他節(jié)點(diǎn)得不到主節(jié)點(diǎn)的響應(yīng)認(rèn)為主節(jié)點(diǎn)掛掉了,會重新選取主節(jié)點(diǎn)。 ? 內(nèi)存回收:data 節(jié)點(diǎn)上的 ES 進(jìn)程占用的內(nèi)存較大,引發(fā) JVM 的大規(guī)模內(nèi)存回收,造成 ES 進(jìn)程失去 響應(yīng)。 腦裂問題解決方案: ? 減少誤判:discovery.zen.ping_timeout 節(jié)點(diǎn)狀態(tài)的響應(yīng)時間,默認(rèn)為 3s,可以適當(dāng)調(diào)大,如果 master在該響應(yīng)時間的范圍內(nèi)沒有做出響應(yīng)應(yīng)答,判斷該節(jié)點(diǎn)已經(jīng)掛掉了。調(diào)大參數(shù)(如 6s,discovery.zen.ping_timeout:6),可適當(dāng)減少誤判。 ? 選舉觸發(fā): discovery.zen.minimum_master_nodes:1 該參數(shù)是用于控制選舉行為發(fā)生的最小集群主節(jié)點(diǎn)數(shù)量。當(dāng)備選主節(jié)點(diǎn)的個數(shù)大于等于該參數(shù)的值,且備選主節(jié)點(diǎn)中有該參數(shù)個節(jié)點(diǎn)認(rèn)為主節(jié)點(diǎn)掛了,進(jìn)行選舉。官方建議為(n/2)+1,n 為主節(jié)點(diǎn)個數(shù)(即有資格成為主節(jié)點(diǎn)的節(jié)點(diǎn)個數(shù)) ? 角色分離:即 master 節(jié)點(diǎn)與 data 節(jié)點(diǎn)分離,限制角色 主節(jié)點(diǎn)配置為:node.master: true node.data: false 從節(jié)點(diǎn)配置為:node.master: false node.data: true
Elasticsearch 索引文檔的流程?
?文章來源地址http://www.zghlxwxcb.cn/news/detail-775649.html
? 協(xié)調(diào)節(jié)點(diǎn)默認(rèn)使用文檔 ID 參與計(jì)算(也支持通過 routing),以便為路由提供合適的分片:shard = hash(document_id) % (num_of_primary_shards) ? 當(dāng)分片所在的節(jié)點(diǎn)接收到來自協(xié)調(diào)節(jié)點(diǎn)的請求后,會將請求寫入到 Memory Buffer,然后定時(默認(rèn) 是每隔 1 秒)寫入到 Filesystem Cache,這個從 Memory Buffer 到 Filesystem Cache 的過程就叫做 refresh; ? 當(dāng)然在某些情況下,存在 Momery Buffer 和 Filesystem Cache 的數(shù)據(jù)可能會丟失,ES 是通過 translog的機(jī)制來保證數(shù)據(jù)的可靠性的。其實(shí)現(xiàn)機(jī)制是接收到請求后,同時也會寫入到 translog 中,當(dāng) Filesystem cache 中的數(shù)據(jù)寫入到磁盤中時,才會清除掉,這個過程叫做 flush; ? 在 flush 過程中,內(nèi)存中的緩沖將被清除,內(nèi)容被寫入一個新段,段的 fsync 將創(chuàng)建一個新的提交點(diǎn),并將內(nèi)容刷新到磁盤,舊的 translog 將被刪除并開始一個新的 translog。 ? flush 觸發(fā)的時機(jī)是定時觸發(fā)(默認(rèn) 30 分鐘)或者 translog 變得太大(默認(rèn)為 512M)時;
Elasticsearch 更新和刪除文檔的流程?
? 刪除和更新也都是寫操作,但是 Elasticsearch 中的文檔是不可變的,因此不能被刪除或者改動以展示其變更; ? 磁盤上的每個段都有一個相應(yīng)的.del 文件。當(dāng)刪除請求發(fā)送后,文檔并沒有真的被刪除,而是在.del文件中被標(biāo)記為刪除。該文檔依然能匹配查詢,但是會在結(jié)果中被過濾掉。當(dāng)段合并時,在.del 文件中被標(biāo)記為刪除的文檔將不會被寫入新段。 ? 在新的文檔被創(chuàng)建時,Elasticsearch 會為該文檔指定一個版本號,當(dāng)執(zhí)行更新時,舊版本的文檔在.del文件中被標(biāo)記為刪除,新版本的文檔被索引到一個新段。舊版本的文檔依然能匹配查詢,但是會在結(jié)果中被過濾掉。
Elasticsearch 搜索的流程?
文章來源:http://www.zghlxwxcb.cn/news/detail-775649.html
?
? 搜索被執(zhí)行成一個兩階段過程,我們稱之為 Query Then Fetch; ? 在初始查詢階段時,查詢會廣播到索引中每一個分片拷貝(主分片或者副本分片)。 每個分片在本地執(zhí)行搜索并構(gòu)建一個匹配文檔的大小為 from + size 的優(yōu)先隊(duì)列。PS:在搜索的時候是會查詢Filesystem Cache 的,但是有部分?jǐn)?shù)據(jù)還在 Memory Buffer,所以搜索是近實(shí)時的。 ? 每個分片返回各自優(yōu)先隊(duì)列中 所有文檔的 ID 和排序值 給協(xié)調(diào)節(jié)點(diǎn),它合并這些值到自己的優(yōu)先隊(duì)列中來產(chǎn)生一個全局排序后的結(jié)果列表。 ? 接下來就是取回階段,協(xié)調(diào)節(jié)點(diǎn)辨別出哪些文檔需要被取回并向相關(guān)的分片提交多個 GET 請求。每個分片加載并豐富文檔,如果有需要的話,接著返回文檔給協(xié)調(diào)節(jié)點(diǎn)。一旦所有的文檔都被取回了,協(xié)調(diào)節(jié)點(diǎn)返回結(jié)果給客戶端。 ? Query Then Fetch 的搜索類型在文檔相關(guān)性打分的時候參考的是本分片的數(shù)據(jù),這樣在文檔數(shù)量較少的時候可能不夠準(zhǔn)確,DFS Query Then Fetch 增加了一個預(yù)查詢的處理,詢問 Term 和 Document frequency,這個評分更準(zhǔn)確,但是性能會變差。
Elasticsearch 在部署時,對 Linux 的設(shè)置有哪些優(yōu)化方法?
? 64 GB 內(nèi)存的機(jī)器是非常理想的,但是 32 GB 和 16 GB 機(jī)器也是很常見的。少于 8 GB 會適得其反。 ? 如果你要在更快的 CPUs 和更多的核心之間選擇,選擇更多的核心更好。多個內(nèi)核提供的額外并發(fā)遠(yuǎn)勝過稍微快一點(diǎn)點(diǎn)的時鐘頻率。 ? 如果你負(fù)擔(dān)得起 SSD,它將遠(yuǎn)遠(yuǎn)超出任何旋轉(zhuǎn)介質(zhì)。 基于 SSD 的節(jié)點(diǎn),查詢和索引性能都有提升。如果你負(fù)擔(dān)得起,SSD 是一個好的選擇。 ? 即使數(shù)據(jù)中心們近在咫尺,也要避免集群跨越多個數(shù)據(jù)中心。絕對要避免集群跨越大的地理距離。 ? 請確保運(yùn)行你應(yīng)用程序的 JVM 和服務(wù)器的 JVM 是完全一樣的。 在 Elasticsearch 的幾個地方,使用 Java 的本地序列化。 ? 通過設(shè)置 gateway.recover_after_nodes、gateway.expected_nodesgateway.recover_after_time 可以在集群重啟的時候避免過多的分片交換,這可能會讓數(shù)據(jù)恢復(fù)從數(shù)個小時縮短為幾秒鐘。 ? Elasticsearch 默認(rèn)被配置為使用單播發(fā)現(xiàn),以防止節(jié)點(diǎn)無意中加入集群。只有在同一臺機(jī)器上運(yùn)行的節(jié)點(diǎn)才會自動組成集群。最好使用單播代替組播。 ? 不要隨意修改垃圾回收器(CMS)和各個線程池的大小。 ? 把你的內(nèi)存的(少于)一半給 Lucene(但不要超過 32 GB!),通過 ES_HEAP_SIZE 環(huán)境變量設(shè)置。 ? 內(nèi)存交換到磁盤對服務(wù)器性能來說是致命的。如果內(nèi)存交換到磁盤上,一個 100 微秒的操作可能變成 10 毫秒。 再想想那么多 10 微秒的操作時延累加起來。 不難看出 swapping 對于性能是多么可怕。 ? Lucene 使用了大量的文件。同時,Elasticsearch 在節(jié)點(diǎn)和 HTTP 客戶端之間進(jìn)行通信也使用了大量的套接字。 所有這一切都需要足夠的文件描述符。你應(yīng)該增加你的文件描述符,設(shè)置一個很大的值,如 64,000。
補(bǔ)充:索引階段性能提升方法
? 使用批量請求并調(diào)整其大?。好看闻繑?shù)據(jù) 5–15 MB 大是個不錯的起始點(diǎn)。 ? 存儲:使用 SSD ? 段和合并:Elasticsearch 默認(rèn)值是 20 MB/s,對機(jī)械磁盤應(yīng)該是個不錯的設(shè)置。如果你用的是 SSD,可以考慮提高到 100–200 MB/s。如果你在做批量導(dǎo)入,完全不在意搜索,你可以徹底關(guān)掉合并限流。另外還可以增加 index.translog.flush_threshold_size 設(shè)置,從默認(rèn)的 512 MB 到更大一些的值,比如 1 GB,這可以在一次清空觸發(fā)的時候在事務(wù)日志里積累出更大的段。 ? 如果你的搜索結(jié)果不需要近實(shí)時的準(zhǔn)確度,考慮把每個索引的 index.refresh_interval 改到 30s。 ? 如果你在做大批量導(dǎo)入,考慮通過設(shè)置 index.number_of_replicas: 0 關(guān)閉副本。
GC 方面,在使用 Elasticsearch 時要注意什么?
? 倒排詞典的索引需要常駐內(nèi)存,無法 GC,需要監(jiān)控 data node 上 segment memory 增長趨勢。 ? 各類緩存,field cache, filter cache, indexing cache, bulk queue 等等,要設(shè)置合理的大小,并且要應(yīng)該根據(jù)最壞的情況來看 heap 是否夠用,也就是各類緩存全部占滿的時候,還有 heap 空間可以分配給其他任務(wù)嗎?避免采用 clear cache 等“自欺欺人”的方式來釋放內(nèi)存。 ? 避免返回大量結(jié)果集的搜索與聚合。確實(shí)需要大量拉取數(shù)據(jù)的場景,可以采用 scan & scroll api 來實(shí)現(xiàn)。 ? cluster stats 駐留內(nèi)存并無法水平擴(kuò)展,超大規(guī)模集群可以考慮分拆成多個集群通過 tribe node 連接。 ? 想知道 heap 夠不夠,必須結(jié)合實(shí)際應(yīng)用場景,并對集群的 heap 使用情況做持續(xù)的監(jiān)控。
Elasticsearch 對于大數(shù)據(jù)量(上億量級)的聚合如何實(shí)現(xiàn)?
Elasticsearch 提供的首個近似聚合是 cardinality 度量。它提供一個字段的基數(shù),即該字段的 distinct或者 unique 值的數(shù)目。它是基于 HLL 算法的。HLL 會先對我們的輸入作哈希運(yùn)算,然后根據(jù)哈希運(yùn)算的結(jié)果中的 bits 做概率估算從而得到基數(shù)。其特點(diǎn)是:可配置的精度,用來控制內(nèi)存的使用(更精確 = 更多內(nèi)存);小的數(shù)據(jù)集精度是非常高的;我們可以通過配置參數(shù),來設(shè)置去重需要的固定內(nèi)存使用量。無論數(shù)千還是數(shù)十億的唯一值,內(nèi)存使用量只與你配置的精確度相關(guān)
在并發(fā)情況下,Elasticsearch 如果保證讀寫一致?
? 可以通過版本號使用樂觀并發(fā)控制,以確保新版本不會被舊版本覆蓋,由應(yīng)用層來處理具體的沖突; ? 另外對于寫操作,一致性級別支持 quorum/one/all,默認(rèn)為 quorum,即只有當(dāng)大多數(shù)分片可用時才允許寫操作。但即使大多數(shù)可用,也可能存在因?yàn)榫W(wǎng)絡(luò)等原因?qū)е聦懭敫北臼?,這樣該副本被認(rèn)為故障,分片將會在一個不同的節(jié)點(diǎn)上重建。 ? 對于讀操作,可以設(shè)置 replication 為 sync(默認(rèn)),這使得操作在主分片和副本分片都完成后才會返回;如果設(shè)置 replication 為 async 時,也可以通過設(shè)置搜索請求參數(shù)_preference 為 primary 來查詢主分片,確保文檔是最新版本.
如何監(jiān)控 Elasticsearch 集群狀態(tài)?
elasticsearch-head 插件 通過 Kibana 監(jiān)控 Elasticsearch。你可以實(shí)時查看你的集群健康狀態(tài)和性能,也可以分析過去的集群、索引和節(jié)點(diǎn)指標(biāo)
Elasticsearch 中的集群、節(jié)點(diǎn)、索引、文檔、類型是什么?
? 集群是一個或多個節(jié)點(diǎn)(服務(wù)器)的集合,它們共同保存您的整個數(shù)據(jù),并提供跨所有節(jié)點(diǎn)的聯(lián)合索引和搜索功能。群集由唯一名稱標(biāo)識,默認(rèn)情況下為“elasticsearch”。此名稱很重要,因?yàn)槿绻?jié)點(diǎn)設(shè)置為按名稱加入群集,則該節(jié)點(diǎn)只能是群集的一部分。 ? 節(jié)點(diǎn)是屬于集群一部分的單個服務(wù)器。它存儲數(shù)據(jù)并參與群集索引和搜索功能。 ? 索引就像關(guān)系數(shù)據(jù)庫中的“數(shù)據(jù)庫”。它有一個定義多種類型的映射。索引是邏輯名稱空間,映射到一個或多個主分片,并且可以有零個或多個副本分片。 MySQL =>數(shù)據(jù)庫 Elasticsearch =>索引 ? 文檔類似于關(guān)系數(shù)據(jù)庫中的一行。不同之處在于索引中的每個文檔可以具有不同的結(jié)構(gòu)(字段),但是對于通用字段應(yīng)該具有相同的數(shù)據(jù)類型。 MySQL => Databases => Tables => Columns / Rows Elasticsearch => Indices => Types =>具有屬性的文檔 ? 類型是索引的邏輯類別/分區(qū),其語義完全取決于用戶。
Elasticsearch 中的倒排索引是什么?
倒排索引是搜索引擎的核心。搜索引擎的主要目標(biāo)是在查找發(fā)生搜索條件的文檔時提供快速搜索。ES中的倒排索引其實(shí)就是 lucene 的倒排索引,區(qū)別于傳統(tǒng)的正向索引,倒排索引會再存儲數(shù)據(jù)時將關(guān)鍵詞和數(shù)據(jù)進(jìn)行關(guān)聯(lián),保存到倒排表中,然后查詢時,將查詢內(nèi)容進(jìn)行分詞后在倒排表中進(jìn)行查詢,最后匹配數(shù)據(jù)即可。
到了這里,關(guān)于elasticsearch7基礎(chǔ)用法及java中使用的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!