Elasticsearch 基礎(chǔ)知識(shí)及安裝異常處理

今天要修改原來的代碼, 重新安裝了ElasticSearch, 在安裝過程中發(fā)生了一些問題, 剛好在搜索到這篇文章, 遇到的問題剛好在這都能找到, 贊一個(gè)!

原文引用 : Elasticsearch學(xué)習(xí)筆記 : https://www.cnblogs.com/zhjh256/p/7446754.html

簡(jiǎn)述

關(guān)于采用mongodb等nosql還是es作為存儲(chǔ)機(jī)制,網(wǎng)上有一些討論,LZ推薦參考https://blog.csdn.net/awdac/article/details/78117393冀续,簡(jiǎn)單地說就是es可以認(rèn)為是相比redis更加智能的加速層早抠,但是它不應(yīng)該作為直接存儲(chǔ)機(jī)制叙谨,這一點(diǎn)和很多數(shù)據(jù)庫的緩存機(jī)制是類似的荸频,例如oracle的結(jié)果集緩存、timesten乾翔,mysql的query cache籽腕,只不過針對(duì)的場(chǎng)景不同嗡呼,例如可以結(jié)合語義搜索。所以它的寫入效率是比較低的皇耗,同時(shí)相比redis而言南窗,它要重的多。

  • Wikipedia使用Elasticsearch作為全文檢索的工具
  • GitHub使用Elasticsearch搜索代碼
  • 基于Lucene郎楼,Elasticsearch之于SQL万伤,Lucene就像RDBMS引擎
  • 使用java編寫

基本配置

  • 啟動(dòng) ./bin/elasticsearch -d 后臺(tái)模式

  • http://localhost:9200/ 查看版本等基本信息

  • 配置文件 config/elasticsearch.yml

  • 原生為集群模式,類似rocketmq和kafka

  • 節(jié)點(diǎn)間使用9300通信

  • 請(qǐng)求格式'<PROTOCOL>://<HOST>/<PATH>?<QUERY_STRING>' -d '<BODY>'呜袁,BODY為JSON編碼的請(qǐng)求體

  • Elasticsearch使用JSON作為序列化格式敌买。

  • 數(shù)據(jù)庫和ES的對(duì)應(yīng)關(guān)系如下:

    • Relational DB ? Databases ? Tables ? Rows ? Columns
    • Elasticsearch ? Indices ? Types ? Documents ? Fields
  • 一個(gè)ES集群包含多個(gè)indices。index是一個(gè)邏輯命名空間阶界,指向一個(gè)或多個(gè)shards虹钮,相當(dāng)于oracle的segment。shard是Lucene的一個(gè)實(shí)例荐操。Shards是Elasticsearch在集群內(nèi)分布數(shù)據(jù)的單位芜抒。Elasticsearch會(huì)根據(jù)cluster的擴(kuò)展和收縮自動(dòng)在節(jié)點(diǎn)間遷移shards珍策。一個(gè)shard可能是primary或replica托启。這跟couchbase的集群管理模式是一樣的。默認(rèn)情況下攘宙,一個(gè)index中有5個(gè)primary shards屯耸。

  • ES日常操作客戶端工具

  • postman(REST命令是下拉,查詢選擇POST即可蹭劈,GET傳遞JSON不便)

  • curl

  • es自帶的客戶端Dev Tools(dev tool有些特殊疗绣,有些命令的兼容性更好reindex)

  • head雖然能用,但是太簡(jiǎn)單铺韧。

    • img

常用操作

查看所有的索引

GET _cat/indices
yellow open wordbaseinfo_new               KFKrcmJoQqWP9kyLzokLQw 1 1 18990   999 174.9mb 174.9mb
yellow open search_doc_new_test            RjfMfH5-Sdmh7rIgNoWRfw 1 1  2261     0  83.9mb  83.9mb
yellow open testsearch                     3nFp58OXSCCDCZKNBSr8yg 1 1     0     0    208b    208b
green  open .kibana-event-log-7.9.0-000004 zrGu0cA0Sle1GHIV2w-szQ 1 0     0     0    208b    208b
green  open .kibana-event-log-7.9.0-000005 8r7NEIxHSeGt1qCX98TFlg 1 0     0     0    208b    208b
green  open .kibana-event-log-7.9.0-000006 KaC-CnfhTDC81EZMUd6XeQ 1 0     0     0    208b    208b
green  open .kibana-event-log-7.9.0-000007 nE_Wv1ibQIW9cRGSt_IZfg 1 0     0     0    208b    208b
green  open .apm-custom-link               CksbWamWQvaafywczHUbwA 1 0     0     0    208b    208b
yellow open fais_search                    OEjrM5YwSJulOhD3T2y7Ig 1 1    64    15   2.6mb   2.6mb
green  open .kibana_task_manager_1         dhMlGVLjQ7Kq-VdrtI6RMg 1 0     6 20650  14.2mb  14.2mb
yellow open inrulebaseinfo_new             om0AqwSPRVqVq6GClq42zQ 1 1     8    10   325kb   325kb
yellow open fais_test                      nDG2Ou9MSyKaShcB4kLzBA 1 1     0     0    208b    208b
yellow open fail_search_test               Gfe4cbi9RX-Dk9fxoAQH3g 1 1 51339    42 907.7mb 907.7mb
yellow open word_item                      W9m8FuFRTzaagZU29y78mw 1 1     0     0    208b    208b
yellow open search_doc_new_ic              tCZigJFUTn6OWEQ3dH013A 1 1 75783     0   2.9gb   2.9gb
yellow open wordbaseinfo_new_for_test      fN12XUf6ScCdkIcI01IhfQ 1 1 18854  8440 139.4mb 139.4mb
yellow open worditem                       uxkzSZToTp6cVkXdwsXSDg 1 1     0     0    208b    208b
green  open .apm-agent-configuration       zaONhEkUTKqnAZbbTzCs0Q 1 0     0     0    208b    208b
yellow open inrulebaseinfo_new_for_test    SWj5BfMWTRyJH8WX7aXCKQ 1 1     0     0    208b    208b
yellow open casebaseinfo                   rfqoCTfGQqOaCNRtbbkS_Q 1 1 17843     0  55.2mb  55.2mb
yellow open time_test                      lW9FMLz1TuKzy6inK-gG0A 1 1     0     0    208b    208b
green  open .kibana_1                      -vM1KSWdQG2zshWD4K0PPg 1 0   615     7  10.4mb  10.4mb
yellow open article                        IpktM1wTSPO6B1Tp-eEiXA 1 1  1056     0   6.1mb   6.1mb
green  open .tasks                         1DlF3FRSSvq2sB4ikpydCw 1 0     5     0  20.2kb  20.2kb
yellow open search_doc_new_ic1             EUNqO51GTTGSycoHYhfZoA 1 1     0     0    208b    208b
yellow open search_doc_new_ic_zjhua        mARAxLD5QBGQFC6VcCdVVA 1 1 75783     0   3.5gb   3.5gb
yellow open casebaseinfo_for_test          Tt9EX2yYSHGDxeunzM4D5g 1 1 16981     0    50mb    50mb

創(chuàng)建索引

PUT http://localhost:9200/blogs

{
    "settings": {
        "number_of_shards": 3,
        "number_of_replicas": 1
    }
}

索引重建

POST _reindex
{
  "source": {
    "index": "search_doc_new_ic"
  },
  "dest": {
    "index": "search_doc_new_ic_zjhua"
  }
}
image

執(zhí)行成功了多矮,但是7.14.1通過GET _tasks?actions=indices:data/write/reindex卻查出來為空。

客戶端容易超時(shí),可以通過GET _tasks?actions=indices:data/write/reindex進(jìn)行監(jiān)控塔逃。

注意點(diǎn):https://www.dazhuanlan.com/dolores63134/topics/1364488

重建索引可能導(dǎo)致數(shù)據(jù)丟失讯壶,見:https://segmentfault.com/q/1010000019003891

還有一種是直接重建(必須是重建)湾盗,以及重建的索引伏蚊,見:https://blog.csdn.net/yexiaomodemo/article/details/97979376

創(chuàng)建文檔

  • 格式:PUT {index}/{type}/{id}需要修改成PUT {index}/_doc/{id}
  • 請(qǐng)求
curl --location --request PUT 'https://elasticsearch.cn/article/601)/1' \
--header 'Content-Type: application/json' \
--data-raw '{
    "first_name": "John",
    "last_name": "Smith",
    "age": 25,
    "about": "I love to go rock climbing",
    "interests": [
        "sports",
        "music"
    ]
}'
  • 響應(yīng)
{"_index":"megacorp","_type":"employee","_id":"2","_version":1,"result":"created","_shards":{"total":2,"successful":1,"failed":0},"created":true}

ES 7.x去掉了

我們一直認(rèn)為ES中的“index”類似于關(guān)系型數(shù)據(jù)庫的“database”格粪,而“type”相當(dāng)于一個(gè)數(shù)據(jù)表躏吊。ES的開發(fā)者們認(rèn)為這是一個(gè)糟糕的認(rèn)識(shí)。例如:關(guān)系型數(shù)據(jù)庫中兩個(gè)數(shù)據(jù)表示是獨(dú)立的帐萎,即使他們里面有相同名稱的列也不影響使用比伏,但ES中不是這樣的。

我們都知道elasticsearch是基于Lucene開發(fā)的搜索引擎疆导,而ES中不同type下名稱相同的filed最終在Lucene中的處理方式是一樣的凳怨。舉個(gè)例子,兩個(gè)不同type下的兩個(gè)user_name是鬼,在ES同一個(gè)索引下其實(shí)被認(rèn)為是同一個(gè)filed肤舞,你必須在兩個(gè)不同的type中定義相同的filed映射。否則均蜜,不同type中的相同字段名稱就會(huì)在處理中出現(xiàn)沖突的情況李剖,導(dǎo)致Lucene處理效率下降。

去掉type能夠使數(shù)據(jù)存儲(chǔ)在獨(dú)立的index中囤耳,這樣即使有相同的字段名稱也不會(huì)出現(xiàn)沖突篙顺,就像ElasticSearch出現(xiàn)的第一句話一樣“你知道的,為了搜索····”充择,去掉type就是為了提高ES處理數(shù)據(jù)的效率德玫。

除此之外,在同一個(gè)索引的不同type下存儲(chǔ)字段數(shù)不一樣的實(shí)體會(huì)導(dǎo)致存儲(chǔ)中出現(xiàn)稀疏數(shù)據(jù)椎麦,影響Lucene壓縮文檔的能力宰僧,導(dǎo)致ES查詢效率的降低。

https://blog.csdn.net/can_do_it/article/details/84884757

https://blog.csdn.net/zjx546391707/article/details/78631394

如果沒有設(shè)置ID观挎,則ES會(huì)自動(dòng)生成一個(gè)琴儿。如:

{
    "_index": "megacorp",
    "_type": "employee",
    "_id": "1",
    "_version": 13,
    "result": "updated",
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "created": false
}

_version代表更改的次數(shù),一般來說嘁捷,id不應(yīng)該自動(dòng)生成造成。

文檔存儲(chǔ)在哪個(gè)shard中的公式如下:shard = hash(routing) % number_of_primary_shards

routing默認(rèn)是_id。
默認(rèn)情況下雄嚣,replication=sync晒屎。默認(rèn)情況下replica=1。
會(huì)自動(dòng)創(chuàng)建index megacorp,聲明類型為employee鼓鲁,編號(hào)為1履肃。

搜索文檔

GET http://localhost:9200/megacorp/employee/1
存在時(shí)如下:

{
    "_index": "megacorp",
    "_type": "employee",
    "_id": "1",
    "_version": 1,
    "found": true,
    "_source": {
        "first_name": "John",
        "last_name": "Smith",
        "age": 25,
        "about": "I love to go rock climbing",
        "interests": [
            "sports",
            "music"
        ]
    }
}

不存在時(shí)如下, 同時(shí)HTTP HEAD為404

{
    "_index": "megacorp",
    "_type": "employee",
    "_id": "111",
    "found": false
}

查詢指定字段

  • 請(qǐng)求 GET http: //localhost:9200/megacorp/employee/1?_source=first_name
{
    "_index": "megacorp",
    "_type": "employee",
    "_id": "1",
    "_version": 13,
    "found": true,
    "_source": {
        "first_name": "John"
    }
}

刪除

  • 請(qǐng)求 DELETE http: //localhost:9200/megacorp/employee/111
{
    "found": true,
    "_index": "megacorp",
    "_type": "employee",
    "_id": "1",
    "_version": 2,
    "result": "deleted",
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    }
}

模糊搜索

精確搜索就沒有必要使用ES了,所以模糊搜索才是關(guān)鍵坐桩。

  • 請(qǐng)求 /_search
{
    "took": 5,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "failed": 0
    },
    "hits": {
        "total": 5,
        "max_score": 1,
        "hits": [
            {
                "_index": "megacorp",
                "_type": "employee",
                "_id": "AV3Kp7BqVnBASvmzDScd",
                "_score": 1,
                "_source": {
                    "first_name": "John",
                    "last_name": "Smith",
                    "age": 25,
                    "about": "I love to go rock climbing",
                    "interests": [
                        "sports",
                        "music"
                    ]
                }
            },
            {
                "_index": "megacorp",
                "_type": "employee",
                "_id": "2",
                "_score": 1,
                "_source": {
                    "first_name": "Jane",
                    "last_name": "Smith",
                    "age": 32,
                    "about": "I like to collect rock albums",
                    "interests": [
                        "music"
                    ]
                }
            },
            {
                "_index": "megacorp",
                "_type": "employee",
                "_id": "AV3Kp5hsVnBASvmzDScc",
                "_score": 1,
                "_source": {
                    "first_name": "John",
                    "last_name": "Smith",
                    "age": 25,
                    "about": "I love to go rock climbing",
                    "interests": [
                        "sports",
                        "music"
                    ]
                }
            },
            {
                "_index": "megacorp",
                "_type": "employee",
                "_id": "1",
                "_score": 1,
                "_source": {
                    "first_name": "John",
                    "last_name": "Smith",
                    "age": 25,
                    "about": "I love to go rock climbing",
                    "interests": [
                        "sports",
                        "music"
                    ]
                }
            },
            {
                "_index": "megacorp",
                "_type": "employee",
                "_id": "3",
                "_score": 1,
                "_source": {
                    "first_name": "Douglas",
                    "last_name": "Fir",
                    "age": 35,
                    "about": "I like to build cabinets",
                    "interests": [
                        "forestry"
                    ]
                }
            }
        ]
    }
}

默認(rèn)情況下尺棋,hits返回符合條件的前面10行,_score從高到低绵跷。如果要分頁膘螟,則需要加上:http://localhost:9200/megacorp/employee/_search?size=2&from=2

搜索所有字段,真正的全文檢索:http://localhost:9200/megacorp/employee/_search?q=John 在后臺(tái)碾局,其實(shí)是查詢所有字段荆残,內(nèi)部有一個(gè)隱含的_all字段,類型為string净当。
各種語法可以參考https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html#query-string-syntax

type/mapping的結(jié)構(gòu)(mapping/模式定義)

GET search_doc_new_ic/_mapping   /* es7之前要用my_index/_mapping/my_type内斯,7去掉了type*/
{
    "search_doc_new_ic": {
        "mappings": {
            "properties": {
                "authors": {
                    "type": "keyword"
                },
                "content": {
                    "properties": {
                        "page_no": {
                            "type": "integer"
                        },
                        "paragraphs": {
                            "type": "text",
                            "index_options": "offsets"
                        }
                    }
                },
                "doc_id": {
                    "type": "keyword"
                },
                "doc_source": {
                    "type": "keyword"
                },
                "file_id": {
                    "type": "keyword"
                },
                "file_name": {
                    "type": "keyword"
                },
                "fstore_group": {
                    "type": "keyword"
                },
                "fstore_path": {
                    "type": "keyword"
                },
                "industry_chain_nodes": {
                    "properties": {
                        "code": {
                            "type": "keyword"
                        },
                        "name": {
                            "type": "keyword"
                        }
                    }
                },
                "industry_chains": {
                    "properties": {
                        "code": {
                            "type": "keyword"
                        },
                        "name": {
                            "type": "keyword"
                        }
                    }
                },
                "industry_code": {
                    "type": "keyword"
                },
                "industry_name": {
                    "type": "keyword"
                },
                "invest_ranking": {
                    "type": "keyword"
                },
                "local_path": {
                    "type": "keyword"
                },
                "org_name": {
                    "type": "keyword"
                },
                "page_count": {
                    "type": "integer"
                },
                "publish_date": {
                    "type": "date"
                },
                "pv": {
                    "type": "integer"
                },
                "report_type": {
                    "type": "keyword"
                },
                "risk_ranking": {
                    "type": "keyword"
                },
                "secu_code": {
                    "type": "keyword"
                },
                "secu_name": {
                    "type": "keyword"
                },
                "sentiment": {
                    "type": "integer"
                },
                "summary": {
                    "type": "text",
                    "index_options": "offsets"
                },
                "title": {
                    "type": "text",
                    "index_options": "offsets"
                }
            }
        }
    }
}

es會(huì)自動(dòng)推斷最合適的類型,比如text/long/date像啼。實(shí)際上ES也是強(qiáng)類型語義的俘闯,如果long被不恰當(dāng)?shù)亩x為string,在全文檢索時(shí)將導(dǎo)致非預(yù)期的結(jié)果忽冻。除了默認(rèn)的定義外真朗,field可以自定義mapping屬性,通常是index(用于控制某字段支持精確匹配僧诚、模糊匹配還是不支持搜索)和analyzer(聲明分析器)這兩個(gè)屬性遮婶。不過mapping不能修改,只能在創(chuàng)建時(shí)或者新增字段時(shí)指定湖笨。

Lucene不支持存儲(chǔ)null值旗扑。

ajax支持

到config文件夾下的elasticsearch.yml,在文件的末尾添加如下內(nèi)容:

http.cors.enabled: true
http.cors.allow-origin: "*"

以便支持在web中通過ajax訪問慈省。

query DSL和filter DSL區(qū)別:query用于全文檢索并得到_score臀防,filter用于精確匹配。
text有精確匹配和全文搜索的區(qū)別辫呻,long/date以及_id則沒有清钥。
Elasticsearch會(huì)為每個(gè)text field的每個(gè)單詞建立inverted index索引。
默認(rèn)情況下放闺,ES區(qū)分大小寫,復(fù)數(shù)與非負(fù)數(shù)缕坎,實(shí)際上我們希望他們不敏感怖侦。還有中文的匹配搜索。這種情況,我們需要使用analyzer匾寝,默認(rèn)的分析器是標(biāo)準(zhǔn)分析器搬葬,它基于UNICODE TEXT SEGMENTATION進(jìn)行分析。ES原生支持的語言分析器包括https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-lang-analyzer.html艳悔,其中不包括中文急凰,所以默認(rèn)每個(gè)漢字都是一個(gè)term。如果不希望某字段使用默認(rèn)的分析器猜年,必須通過在這些字段上聲明mapping(也叫schema definition抡锈,也就是ddl的意思)來手工配置。
  使用DSL語言作為查詢條件的格式乔外,也就是JSON格式床三。所有的查詢結(jié)果都會(huì)返回一個(gè)_score,表示匹配程度杨幼。

問題

Fielddata is disabled on text fields by default. Set fielddata=true on [interests] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory. Alternatively use a keyword field instead.
解決方法:http://blog.csdn.net/u011403655/article/details/71107415
https://www.elastic.co/guide/en/elasticsearch/reference/current/fielddata.html

在cluster中撇簿,有一個(gè)節(jié)點(diǎn)被選為master節(jié)點(diǎn),其負(fù)責(zé)集群內(nèi)的全局管理差购,比如增加/刪除index四瘫、節(jié)點(diǎn),但是不管理具體的事情欲逃。

查看ES集群狀態(tài):

GET http: //localhost:9200/_cluster/health
{
    "cluster_name": "elasticsearch",
    "status": "yellow",
    "timed_out": false,
    "number_of_nodes": 1,
    "number_of_data_nodes": 1,
    "active_primary_shards": 5,
    "active_shards": 5,
    "relocating_shards": 0,
    "initializing_shards": 0,
    "unassigned_shards": 5,
    "delayed_unassigned_shards": 0,
    "number_of_pending_tasks": 0,
    "number_of_in_flight_fetch": 0,
    "task_max_waiting_in_queue_millis": 0,
    "active_shards_percent_as_number": 50
}

最重要的是status字段莲组。取值為:

  • green:All primary and replica shards are active.
  • yellow:All primary shards are active, but not all replica shards are active.(對(duì)于單節(jié)點(diǎn)的環(huán)境來說,replica shards沒有什么意義)
  • red:Not all primary shards are active.

啟動(dòng)第二個(gè)節(jié)點(diǎn)的時(shí)候暖夭,節(jié)點(diǎn)會(huì)自動(dòng)加入相同名稱的cluster.name集群锹杈。Elasticsearch能夠在節(jié)點(diǎn)宕機(jī)后自動(dòng)重新選舉master shard,這樣就可以重新提供服務(wù)了迈着。

查看ES及l(fā)ucene版本

{
  "name" : "t2ztM-f",
  "cluster_name" : "docker-cluster",
  "cluster_uuid" : "DTTrGi_UR12p8Vbc9MTNAQ",
  "version" : {
    "number" : "6.3.2",
    "build_flavor" : "oss",
    "build_type" : "tar",
    "build_hash" : "053779d",
    "build_date" : "2018-07-20T05:20:23.451332Z",
    "build_snapshot" : false,
    "lucene_version" : "7.3.1",
    "minimum_wire_compatibility_version" : "5.6.0",
    "minimum_index_compatibility_version" : "5.0.0"
  },
  "tagline" : "You Know, for Search"
}

Elasticsearch中竭望,文檔中的每個(gè)字段都被索引了,一個(gè)查詢中裕菠。

元數(shù)據(jù)包括:

  • ***index:必須小寫咬清,不能包括逗號(hào),不能開頭
  • _type:每個(gè)type都有自己的模式定義或者稱為mapping
  • _id:唯一標(biāo)識(shí)一個(gè)type內(nèi)的文檔***

默認(rèn)情況下奴潘,ES基于相關(guān)性進(jìn)行排序旧烧。如果要根據(jù)字段進(jìn)行排序,則要指定如下:

GET / _search {
    "query": {
        "filtered": {
            "filter": {
                "term": {
                    "user_id": 1
                }
            }
        }
    },
    "sort": {
        "date": {
            "order": "desc"
        }
    }
}

如果排序不是基于相關(guān)性的話画髓,_score不會(huì)被計(jì)算玖姑。計(jì)算_score的成本很高,所以指定了sort的話厚满,默認(rèn)不會(huì)計(jì)算_score,指定track_scores=true可以強(qiáng)行計(jì)算廉赔。

多條件匹配,首先根據(jù)date匾鸥,其次根據(jù)相關(guān)性蜡塌。

GET / _search {
    "query": {
        "filtered": {
            "query": {
                "match": {
                    "tweet": "manage text search"
                }
            },
            "filter": {
                "term": {
                    "user_id": 2
                }
            }
        }
    },
    "sort": [{
            "date": {
                "order": "desc"
            }
        },
        {
            "_score": {
                "order": "desc"
            }
        }
    ]
}

對(duì)于全文搜索的字段,排序沒有意義勿负,一般用相關(guān)度馏艾。

ES會(huì)將盡可能多的數(shù)據(jù)保存在內(nèi)存中以提高性能。
ES的查詢稱為分布式搜索查詢奴愉,分為查詢和提取兩部分琅摩。在查詢階段,請(qǐng)求會(huì)廣播給所有的shard躁劣,返回符合條件的top N迫吐,根據(jù)order by條件。

查看indices層面的狀態(tài)

GET _cluster/health?level=indices
GET _cluster/health?level=shards
查看節(jié)點(diǎn)的狀態(tài):
http://localhost:9200/_nodes/stats

刪除索引下的所有數(shù)據(jù)账忘,但是不刪除索引本身

POST http://10.20.30.193:9200/search_doc_new_ic/_delete_by_query?refresh
{ "query": { "match_all": {} } }
{
    "took": 147849,
    "timed_out": false,
    "total": 3789150,
    "deleted": 3789150,
    "batches": 3790,
    "version_conflicts": 0,
    "noops": 0,
    "retries": {
        "bulk": 0,
        "search": 0
    },
    "throttled_millis": 0,
    "requests_per_second": -1,
    "throttled_until_millis": 0,
    "failures": []
}

需要注意的是志膀,刪除文檔不會(huì)刪除空間。

image

查詢時(shí)match鳖擒、match_phrase溉浙、query_string三者的區(qū)別

match相當(dāng)于已經(jīng)條件已經(jīng)分詞過,直接傳遞進(jìn)去查找蒋荚。對(duì)應(yīng)pg中xxx::tsquery

query_string相當(dāng)于未分詞過戳稽,傳遞的是原始文本,會(huì)先進(jìn)行分析期升,然后和match一樣惊奇。to_tsquery(xxx,xxx)

match_phrase和match的區(qū)別是,match不是詞組查詢播赁,只要包含即可颂郎,match_phrase有順序要求。phraseto_tsquery(xxx,xxx)

注意點(diǎn)

每個(gè)JVM內(nèi)存不要超過32GB容为,最好在30GB以內(nèi)(postgresql就沒這個(gè)問題)乓序、而且java中堆大了之后,GC也是個(gè)嚴(yán)重的問題坎背,Elasticsearch和Lucene分別使用1/2的內(nèi)存替劈。前者使用JVM內(nèi)存,后者使用OS的filesystem cache得滤。不過如果這樣配置的話陨献,為了保證

HA,需要設(shè)置初始化參數(shù)cluster.routing.allocation.same_shard.host:true耿戚,防止主和從shard分配到相同的機(jī)器湿故。
聚合是通過稱為fielddata的數(shù)據(jù)結(jié)構(gòu)完成的阿趁,F(xiàn)ielddata是Elasticsearch集群中內(nèi)存的最大消耗者膜蛔。所以必須完全理解它坛猪。

Fielddata有點(diǎn)像RDBMS的數(shù)據(jù)塊,只不過應(yīng)該是行為單位的皂股,會(huì)按需加載到內(nèi)存墅茉。Fielddata存在的原因是因?yàn)閕nverted indices不是銀彈,inverted indices擅長(zhǎng)于找到包含某個(gè)分詞(term)的文檔呜呐,但是反過來就斤,在某個(gè)文檔中存在哪些個(gè)term就懵逼了,而聚合需要這種二次訪問模式蘑辑。

ES linux下安裝

  • vi elasticsearch.yml , 配置 network.host: 0.0.0.0 否則只有本機(jī)才能訪問
  • 不能root用戶執(zhí)行洋机,數(shù)據(jù)庫如postgresql、oracle都如此洋魂。
    • groupadd es
    • useradd -g es es
  • [2016-12-20T22:37:28,552][ERROR][o.e.b.Bootstrap ] [elk-node1] node validation exception
    bootstrap checks failed
    • 解決:使用centos 7版本绷旗,就不會(huì)出現(xiàn)此類問題了。
  • system call filters failed to install; check the logs and fix your configuration or disable system call filters at your own risk
    原因 : 這是在因?yàn)镃entos6不支持SecComp副砍,而ES5.2.0默認(rèn)bootstrap.system_call_filter為true進(jìn)行檢測(cè)衔肢,所以導(dǎo)致檢測(cè)失敗,失敗后直接導(dǎo)致ES不能啟動(dòng)豁翎。
    • 解決方法
      • 在elasticsearch.yml中配置bootstrap.system_call_filter為false角骤,注意要在Memory下面:
        • bootstrap.memory_lock: false
        • bootstrap.system_call_filter: false

ES 7報(bào)錯(cuò)

  • 在啟動(dòng)ElasticSearch的過程中爆出了以下錯(cuò)誤:
ERROR: [1] bootstrap checks failed
[1]: the default discovery settings are unsuitable for production use; at least one of [discovery.seed_hosts, discovery.seed_providers, cluster.initial_master_nodes] must be configured

修改 elasticsearch.yml
取消注釋保留一個(gè)節(jié)點(diǎn) cluster.initial_master_nodes: ["node-1"]

  • 另一錯(cuò)誤
[2021-09-18T22:15:24,063][ERROR][o.e.i.g.GeoIpDownloader  ] [node-1] exception during geoip databases update
java.net.ConnectException: Connection refused
    at sun.nio.ch.Net.pollConnect(Native Method) ~[?:?]
    at sun.nio.ch.Net.pollConnectNow(Net.java:669) ~[?:?]
    at sun.nio.ch.NioSocketImpl.timedFinishConnect(NioSocketImpl.java:549) ~[?:?]
    at sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:597) ~[?:?]
    at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:333) ~[?:?]
    at java.net.Socket.connect(Socket.java:645) ~[?:?]
    at sun.security.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:300) ~[?:?]
    at sun.net.NetworkClient.doConnect(NetworkClient.java:177) ~[?:?]
    at sun.net.www.http.HttpClient.openServer(HttpClient.java:497) ~[?:?]
    at sun.net.www.http.HttpClient.openServer(HttpClient.java:600) ~[?:?]
    at sun.net.www.protocol.https.HttpsClient.<init>(HttpsClient.java:265) ~[?:?]
    at sun.net.www.protocol.https.HttpsClient.New(HttpsClient.java:379) ~[?:?]
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.getNewHttpClient(AbstractDelegateHttpsURLConnection.java:189) ~[?:?]
    at sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1232) ~[?:?]
    at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:1120) ~[?:?]
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:175) ~[?:?]
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1653) ~[?:?]
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1577) ~[?:?]
    at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:527) ~[?:?]
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:308) ~[?:?]
    at org.elasticsearch.ingest.geoip.HttpClient.lambda$get$0(HttpClient.java:55) ~[ingest-geoip-7.14.1.jar:7.14.1]
    at java.security.AccessController.doPrivileged(AccessController.java:554) ~[?:?]
    at org.elasticsearch.ingest.geoip.HttpClient.doPrivileged(HttpClient.java:97) ~[ingest-geoip-7.14.1.jar:7.14.1]
    at org.elasticsearch.ingest.geoip.HttpClient.get(HttpClient.java:49) ~[ingest-geoip-7.14.1.jar:7.14.1]
    at org.elasticsearch.ingest.geoip.HttpClient.getBytes(HttpClient.java:40) ~[ingest-geoip-7.14.1.jar:7.14.1]
    at org.elasticsearch.ingest.geoip.GeoIpDownloader.fetchDatabasesOverview(GeoIpDownloader.java:115) ~[ingest-geoip-7.14.1.jar:7.14.1]
    at org.elasticsearch.ingest.geoip.GeoIpDownloader.updateDatabases(GeoIpDownloader.java:103) ~[ingest-geoip-7.14.1.jar:7.14.1]
    at org.elasticsearch.ingest.geoip.GeoIpDownloader.runDownloader(GeoIpDownloader.java:235) [ingest-geoip-7.14.1.jar:7.14.1]
    at org.elasticsearch.ingest.geoip.GeoIpDownloaderTaskExecutor.nodeOperation(GeoIpDownloaderTaskExecutor.java:94) [ingest-geoip-7.14.1.jar:7.14.1]
    at org.elasticsearch.ingest.geoip.GeoIpDownloaderTaskExecutor.nodeOperation(GeoIpDownloaderTaskExecutor.java:43) [ingest-geoip-7.14.1.jar:7.14.1]
    at org.elasticsearch.persistent.NodePersistentTasksExecutor$1.doRun(NodePersistentTasksExecutor.java:40) [elasticsearch-7.14.1.jar:7.14.1]
    at org.elasticsearch.common.util.concurrent.ThreadContext$ContextPreservingAbstractRunnable.doRun(ThreadContext.java:732) [elasticsearch-7.14.1.jar:7.14.1]
    at org.elasticsearch.common.util.concurrent.AbstractRunnable.run(AbstractRunnable.java:26) [elasticsearch-7.14.1.jar:7.14.1]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130) [?:?]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630) [?:?]
    at java.lang.Thread.run(Thread.java:831) [?:?]

原因:此版本將GeoIp功能默認(rèn)開啟了采集。在默認(rèn)的啟動(dòng)下是會(huì)去官網(wǎng)的默認(rèn)地址下獲取最新的Ip的GEO信息心剥。
官方說明 geoip-processor

增加配置 ingest.geoip.downloader.enabled: false即可邦尊。

vi /etc/security/limits.conf
添加如下內(nèi)容:

* soft nofile 65536
* hard nofile 131072
* soft nproc 2048
* hard nproc 4096

vi /etc/sysctl.conf
添加下面配置:
vm.max_map_count=655360
并執(zhí)行命令:
sysctl -p
然后,重新啟動(dòng)elasticsearch优烧,即可啟動(dòng)成功蝉揍。

ES java寫入

https://www.cnblogs.com/chenyuanbo/p/10296827.html

https://www.cnblogs.com/cjsblog/p/10232581.html

java報(bào)錯(cuò)

Caused by: java.lang.ClassNotFoundException: org.elasticsearch.client.Cancellable

原因及解決方法:版本沖突造成,在POM文件中指定版本就行

<properties>
  <java.version>1.8</java.version>
  <elasticsearch.version>7.14.1</elasticsearch.version>
</properties>

node settings must not contain any index level settings

Since elasticsearch 5.x index level settings can NOT be set on the nodes configuration like the elasticsearch.yaml, in system properties or command line arguments.

需要通過REST API設(shè)置索引的內(nèi)容匙隔。例如疑苫,修改translog參數(shù):

http://10.20.30.193:9200/_all/_settings?preserve_existing=true{
  "index.translog.durability":"async",
  "index.translog.sync_interval":"30s",
  "index.translog.flush_threshold_size":"1024mb"
}
{
    "error": {
        "root_cause": [
            {
                "type": "resource_already_exists_exception",
                "reason": "index [search_doc_new_ic/JQR491ldTDKpNum4pWkl7g] already exists",
                "index_uuid": "JQR491ldTDKpNum4pWkl7g",
                "index": "search_doc_new_ic"
            }
        ],
        "type": "resource_already_exists_exception",
        "reason": "index [search_doc_new_ic/JQR491ldTDKpNum4pWkl7g] already exists",
        "index_uuid": "JQR491ldTDKpNum4pWkl7g",
        "index": "search_doc_new_ic"
    },
    "status": 400
}

有一種說法是先關(guān)閉索引,修改纷责,再打開捍掺。但是這個(gè)不應(yīng)該是原因。關(guān)閉之后再膳,索引狀態(tài)就成了unknown(和刪除后的瞬間狀態(tài)一樣)挺勿。查看索引狀態(tài):

{"error":{"root_cause":[{"type":"index_closed_exception","reason":"closed","index_uuid":"ZGJeKccHTiyitcdgqvkVqQ","index":"search_doc_new_ic"}],"type":"index_closed_exception","reason":"closed","index_uuid":"ZGJeKccHTiyitcdgqvkVqQ","index":"search_doc_new_ic"},"status":400}
image

什么時(shí)候需要關(guān)閉索引呢?

有些操作必須先關(guān)閉索引喂柒,才能修改不瓶,例如修改索引的默認(rèn)分詞器禾嫉。

{
    "error": {
        "root_cause": [
            {
                "type": "illegal_argument_exception",
                "reason": "Can't update non dynamic settings [[index.analysis.analyzer.default.type]] for open indices [[search_doc_new_ic/ga3Y8cBgR8iBbyZsgqltMw]]"
            }
        ],
        "type": "illegal_argument_exception",
        "reason": "Can't update non dynamic settings [[index.analysis.analyzer.default.type]] for open indices [[search_doc_new_ic/ga3Y8cBgR8iBbyZsgqltMw]]"
    },
    "status": 400
}

POST http://10.20.30.193:9200/search_doc_new_ic/_close

POST http://10.20.30.193:9200/search_doc_new_ic/_open

elasticsearch開啟慢日志記錄

# 檢查是否開啟慢日志記錄
GET /test/_settings


# 開啟查詢慢日志記錄
PUT /test/_settings
{
    "index.search.slowlog.threshold.query.warn": "1000ms",
    "index.search.slowlog.threshold.query.info": "500ms",
    "index.search.slowlog.threshold.query.debug": "800ms",
    "index.search.slowlog.threshold.query.trace": "200ms",
    "index.search.slowlog.threshold.fetch.warn": "1000ms",
    "index.search.slowlog.threshold.fetch.info": "500ms",
    "index.search.slowlog.threshold.fetch.debug": "800ms",
    "index.search.slowlog.threshold.fetch.trace": "200ms",
    "index.search.slowlog.level": debug
}

# 開啟索引慢日志記錄
PUT /test/_settings
{
    "index.indexing.slowlog.threshold.index.warn": "1000ms",
    "index.indexing.slowlog.threshold.index.info": "500ms",
    "index.indexing.slowlog.threshold.index.debug": "500ms",
    "index.indexing.slowlog.threshold.index.trace": "500ms",
    "index.indexing.slowlog.level": debug,
    "index.indexing.slowlog.source": 1000
}

關(guān)閉慢日志

PUT /test/_settings
{
    "index.indexing.slowlog.threshold.index.warn": null,
    "index.indexing.slowlog.threshold.index.info": null,
    "index.indexing.slowlog.threshold.index.debug": null,
    "index.indexing.slowlog.threshold.index.trace": null,
    "index.indexing.slowlog.level": null,
    "index.indexing.slowlog.source": null
}

查看執(zhí)行計(jì)劃

GET shopping/_search
{
  "explain": true, 
  "query": {
    "match": {
        "goodsInfoName": "蘇泊爾"
    }
  }
}

輸出如下

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 3,
    "successful" : 3,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 24,
      "relation" : "eq"
    },
    "max_score" : 5.3067513,
    "hits" : [
      {
        "_shard" : "[shopping][1]",
        "_node" : "h665-yAdSzGgjxamBh5CjA",
        "_index" : "shopping",
        "_type" : "_doc",
        "_id" : "10976",
        "_score" : 5.3067513,
        "_source" : {
           "goodsInfoName" : "蘇泊爾不銹鋼壓力鍋高壓鍋YS22ED+蘇泊爾保鮮盒飯盒便當(dāng)盒330mlKB033AE1(銀色)",
           "其他字段省略....."
        },
        "_explanation" : {
          "value" : 5.3067513,
          "description" : "weight(goodsInfoName:蘇泊爾 in 328) [PerFieldSimilarity], result of:",
          "details" : [
            {
              "value" : 5.3067513,
              "description" : "score(freq=2.0), computed as boost * idf * tf from:",
              "details" : [
                {
                  "value" : 2.2,
                  "description" : "boost",
                  "details" : [ ]
                },
                {
                  "value" : 3.6549778,
                  "description" : "idf, computed as log(1 + (N - n + 0.5) / (n + 0.5)) from:",
                  "details" : [
                    {
                      "value" : 10,
                      "description" : "n, number of documents containing term",
                      "details" : [ ]
                    },
                    {
                      "value" : 405,
                      "description" : "N, total number of documents with field",
                      "details" : [ ]
                    }
                  ]
                },
                {
                  "value" : 0.65996563,
                  "description" : "tf, computed as freq / (freq + k1 * (1 - b + b * dl / avgdl)) from:",
                  "details" : [
                    {
                      "value" : 2.0,
                      "description" : "freq, occurrences of term within document",
                      "details" : [ ]
                    },
                    {
                      "value" : 1.2,
                      "description" : "k1, term saturation parameter",
                      "details" : [ ]
                    },
                    {
                      "value" : 0.75,
                      "description" : "b, length normalization parameter",
                      "details" : [ ]
                    },
                    {
                      "value" : 11.0,
                      "description" : "dl, length of field",
                      "details" : [ ]
                    },
                    {
                      "value" : 13.553086,
                      "description" : "avgdl, average length of field",
                      "details" : [ ]
                    }
                  ]
                }
              ]
            }
          ]
        }
      }

性能優(yōu)化

  • 禁用不需要索引的字段。設(shè)置屬性"index":"not_analyzed"(只支持精確匹配蚊丐,適合于日期熙参、數(shù)字字段,5.x版本開始麦备,也可以設(shè)置類型為keyword表示不分詞)孽椰。最為重要。

  • 禁用_all字段凛篙。

  • 對(duì)字段不分詞,或者不索引,可以節(jié)省很多運(yùn)算,降低 CPU 占用.尤其是 binary 類型,默認(rèn)情況下占用 CPU 非常高,而這種類型根本不需要進(jìn)行分詞做索引黍匾。單個(gè) doc 在建立索引時(shí)的運(yùn)算復(fù)雜度,最大的因素 不在于 doc 的字節(jié)數(shù)或者說某個(gè)字段 value 的長(zhǎng)度,而是字段的數(shù)量. 例如在滿負(fù)載的寫入壓力測(cè)試中,mapping 相同的情況下,一個(gè)有10個(gè)字段,200字節(jié)的 doc, 通過增加某些字段 value 的長(zhǎng)度到500字節(jié),寫入 es 時(shí)速度下降很少,而如果字段數(shù)增加到20,即使整個(gè) doc 字節(jié)數(shù)沒增加多少,寫入速度也會(huì)降低一倍。

索引

默認(rèn)情況下呛梆,ES索引默認(rèn)情況下每秒鐘刷新一次锐涯。因?yàn)閿?shù)據(jù)插入到ES時(shí)候,先到了in-memory buffer填物,此時(shí)是對(duì)外不可見的纹腌。只有被索引(分詞和建立反轉(zhuǎn)索引的過程)之后,才對(duì)外可見融痛。一般會(huì)調(diào)整為30s或更多壶笼,具體多少合適,要看目標(biāo)機(jī)器index的速度以及插入的TPS雁刷。設(shè)置為-1不意味著不索引了覆劈,只是索引是個(gè)被動(dòng)的過程,當(dāng)translog滿了之后沛励,還是會(huì)索引的责语。可見https://stackoverflow.com/questions/36449506/what-exactly-does-1-refresh-interval-in-elasticsearch-mean目派。

indices.memory.index_buffer_size: 10%* -Xmx

事務(wù)日志優(yōu)化

index.translog.durability:aysnc

index.translog.sync_interval:120s

index.translog.flush_threshold_size:1024mb

分片數(shù)量控制

分片越大坤候,索引速度越慢,尤其是單個(gè)分片超過幾十GB后企蹭。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末白筹,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子谅摄,更是在濱河造成了極大的恐慌徒河,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,723評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件送漠,死亡現(xiàn)場(chǎng)離奇詭異顽照,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)闽寡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門代兵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來尼酿,“玉大人,你說我怎么就攤上這事植影∩亚妫” “怎么了?”我有些...
    開封第一講書人閱讀 152,998評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵何乎,是天一觀的道長(zhǎng)句惯。 經(jīng)常有香客問我土辩,道長(zhǎng)支救,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,323評(píng)論 1 279
  • 正文 為了忘掉前任拷淘,我火速辦了婚禮各墨,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘启涯。我一直安慰自己贬堵,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評(píng)論 5 374
  • 文/花漫 我一把揭開白布结洼。 她就那樣靜靜地躺著黎做,像睡著了一般。 火紅的嫁衣襯著肌膚如雪松忍。 梳的紋絲不亂的頭發(fā)上蒸殿,一...
    開封第一講書人閱讀 49,079評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音鸣峭,去河邊找鬼宏所。 笑死,一個(gè)胖子當(dāng)著我的面吹牛摊溶,可吹牛的內(nèi)容都是我干的爬骤。 我是一名探鬼主播,決...
    沈念sama閱讀 38,389評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼莫换,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼霞玄!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起拉岁,我...
    開封第一講書人閱讀 37,019評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤坷剧,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后膛薛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體听隐,經(jīng)...
    沈念sama閱讀 43,519評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評(píng)論 2 325
  • 正文 我和宋清朗相戀三年哄啄,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了雅任。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片风范。...
    茶點(diǎn)故事閱讀 38,100評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖沪么,靈堂內(nèi)的尸體忽然破棺而出硼婿,到底是詐尸還是另有隱情,我是刑警寧澤禽车,帶...
    沈念sama閱讀 33,738評(píng)論 4 324
  • 正文 年R本政府宣布寇漫,位于F島的核電站,受9級(jí)特大地震影響殉摔,放射性物質(zhì)發(fā)生泄漏州胳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評(píng)論 3 307
  • 文/蒙蒙 一逸月、第九天 我趴在偏房一處隱蔽的房頂上張望栓撞。 院中可真熱鬧,春花似錦碗硬、人聲如沸瓤湘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽弛说。三九已至,卻和暖如春翰意,著一層夾襖步出監(jiān)牢的瞬間木人,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工猎物, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留虎囚,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,547評(píng)論 2 354
  • 正文 我出身青樓蔫磨,卻偏偏與公主長(zhǎng)得像淘讥,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子堤如,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容