Elasticsearch遇到的坑

一、內存不夠不能啓動
Java HotSpot(TM) Server VM warning: INFO: os::commit_memory(0xcc000000, 469762048, 0) failed; error='Cannot allocate memory' (errno=12)
#
# There is insufficient memory for the Java Runtime Environment to continue.
# Native memory allocation (mmap) failed to map 469762048 bytes for committing reserved memory.
# An error report file with more information is saved as:
# /usr/local/elasticsearch/bin/hs_err_pid7598.log

解決:一開始我是把這兩個參數往大了調還是不行,其實是應該往小了調,一開始是12g,我給調成了15g不行,調成8g就可以了。(物理硬盤內存小而jvm的內存分配過大所導致)

# vi /usr/local/elasticsearch/config/jvm.options
-Xms8g
-Xmx8g

 

二、更新衝突

問題描述:手機APP端兩個用戶同時評論一篇文章該篇文章的評論量只增加了1。
 
問題代碼:

XContentBuilder updateSource = XContentFactory.jsonBuilder().startObject()
		.field("atdCnt", atdCnt + 1).endObject();
updateResponse = getTransportClient()
		.prepareUpdate(esProperties.getES_Index(), esProperties.getES_Type(), docID)
		.setRouting(esProperties.getES_Routing()).setDoc(updateSource).get();

解決:

UpdateRequest updateRequest = new UpdateRequest();  
updateRequest.index(esProperties.getES_Index());  
updateRequest.type(esProperties.getES_Type());  
updateRequest.id(docID);
updateRequest.routing(esProperties.getES_Routing());
updateRequest.script(new Script("ctx._source.cmtCnt++")).retryOnConflict(2);
updateResponse = getTransportClient().update(updateRequest).get();

參考:
https://blog.csdn.net/qq_35431789/article/details/78653554
 

三、搜索term和terms的區別
GET xiaoqiang-2019-1-28/News/_search
{
    "query": {
        "terms":{
            "mediaTname":"APP"
        }
    }
}

報錯:

{
  "error": {
    "root_cause": [
      {
        "type": "parsing_exception",
        "reason": "[terms] query does not support [mediaTname]",
        "line": 4,
        "col": 42
      }
    ],
    "type": "parsing_exception",
    "reason": "[terms] query does not support [mediaTname]",
    "line": 4,
    "col": 42
  },
  "status": 400
}

在查詢的字段只有一個值的時候,應該使用term而不是terms,在查詢字段包含多個的時候才使用terms,使用terms語法,JSON中必須包含數組。
正確的寫法:

第一種(單個值,term):
GET xiaoqiang-2019-1-28/News/_search
{
    "query": {
        "term":{
            "mediaTname":"APP"
        }
    }
}

第二種(數組形式,terms):
GET xiaoqiang-2019-1-28/News/_search
{
    "query": {
        "terms":{
            "mediaTname":["APP","新聞"]
        }
    }
}

 

四、聚合時提示illegal_argument_exception
GET xiao-2018-4-1/Socials/_search
{
    "size" : 0,    //取出前幾條數據
    "query" : {    //可以先使用query查詢得到需要的數據集
        "term" : {
            "website" : "微信"
        }
    },
    "aggs" : {
        "single_sum": {    //這個名字隨便起
            "sum" : { "field" : "flwCnt" }    //這個必須是number類型字段,flwCnt字段爲關注量
        }
    }
}

注意:在執行上面命令的時候遇到了illegal_argument_exception報錯,報錯信息如下

{
  "error": {
    "root_cause": [
      {
        "type": "illegal_argument_exception",
        "reason": "Fielddata is disabled on text fields by default. Set fielddata=true on [website] 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."
      }
    ],
    "type": "search_phase_execution_exception",
    "reason": "all shards failed",
    "phase": "query",
    "grouped": true,
    "failed_shards": [
      {
        "shard": 0,
        "index": "xiao-2018-4-1",
        "node": "Vux5eT5mTg2iiiiiiiiiii",
        "reason": {
          "type": "illegal_argument_exception",
          "reason": "Fielddata is disabled on text fields by default. Set fielddata=true on [website] 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."
        }
      }
    ]
  },
  "status": 400
}

注:該website字段的mapping爲(這種情況是在一開始創建mapping的時候並沒有定義website字段,但在插入數據的時候有該字段,則es會默認自動創建下面的動態映射)

          "website": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          }

解決:
方法一:修改mapping,增加“預加載 fielddata”
在ElasticSearch中fielddata默認是false的,因爲開啓Text的fielddata後對內存的佔用很高

方法二:(推薦使用該方法)在這個website字段後面加.keyword

補充:
隨着ElasticSearch 5.0的到來, 同時也迎來了該版本的重大特性之一: 移除了string類型. 這個變動的根本原因是string類型會給我們帶來很多困惑: 因爲ElasticSearch對字符串擁有兩種完全不同的搜索方式. 你可以按照整個文本進行匹配, 即關鍵詞搜索(keyword search), 也可以按單個字符匹配, 即全文搜索(full-text search). 對ElasticSearch稍有了解的人都知道, 前者的字符串被稱爲not-analyzed字符, 而後者被稱作analyzed字符串.

事實上, 同一種類型用於應對兩種不同的使用場景是會讓人崩潰的, 因爲有些選項只對其一的場景設置有效.例如position_increment_gap對not-analyzed字符就不會起作用, 而像ignore_above對於analyzed字符串就很難區分它到底是對整個字符串的值有效還是對單獨的每個分詞有效(在這種場景, ignore_above確實只對整個字符串值有效, 而對單個分詞的限制可以使用limit設置).

爲了避免上述尷尬, string字段被拆分成兩種新的數據類型: text用於全文搜索的, 而keyword用於關鍵詞搜索.

做了這個類型分解之後, 我們對string字段的默認dynamic mappings 也做了改變. 在以前剛接觸ElasticSearch時, 如果需要對某個字段的所有取值做聚合, 你不得不對這些數據重做索引. 假如你正在處理的文檔中包含一個city字段. 對這個字段做聚合的話會分別給出new和york的總數, 而非我們通常期望的New York的總數.讓人沮喪的是爲了達到我們希望的結果, 我們必須對這個字段重新進行索引.

爲了不讓事情變得這麼糟糕, ElasticSearch決定從Logstash中借取思路: 字符串將默認被同時映射成text和keyword類型. 例如對下面的文檔進行索引後:

{
    "foo": "bar"
}

text類型:支持分詞、全文檢索,不支持聚合、排序操作。
適合大字段存儲,如:文章詳情、content字段等;

keyword類型:支持精確匹配,支持聚合、排序操作。
適合精準字段匹配,如:url、name、title等字段。
一般情況,text和keyword共存。

如ElasticSearch將會爲你創建下面的動態映射(dynamic mappings):

{
    "foo": {
        "type": "text",
        "fields": {
            "keyword": {
                "type": "keyword",
                "ignore_above": 256
            }
        }
    }
}

當然, 基於這個映射你即可以在foo字段上進行全文搜索, 也可以通過foo.keyword字段實現關鍵詞搜索及數據聚合.

禁用這個特性也很方便: 你只需要在定義mapping時顯式聲明字符串字段的類型或者使用一個動態模板(dynamic template)來匹配你所有的字符串字段即可. 例如通過下面的dynamic template就可以恢復到在ElasticSearch 2.x中使用的dynamic template的效果:

{
    "match_mapping_type": "string",
    "mapping": {
        "type": "text"
    }
}

如何遷移到新版本
通常, 遷移工作是非常容易的. 以前映射到analyzed的字符串的字段:

{
    "foo": {
        "type": "string",
        "index": "analyzed"
    }
}

如今只要映射爲text即可:

{
    "foo": {
        "type": "text",
        "index": true
    }
}

以前被定義爲not_analyzed的字符串字段:

{
    "foo": {
        "type": "string",
        "index": "not_analyzed"
    }
}

也只需要被定義爲keyword即可:

{
    "foo": {
        "type": "keyword",
        "index": true
    }
}

如上所述, string字段被重新定義爲text和keyword字段. 對於上面的index屬性, 因爲在新的定義中我們不需要三種狀態(在以前的string定義中可以是analyzed, not_analyzed和no), 所以只簡單的定義成了boolean值, 以告知ElasticSearch是否可在該字段上進行搜索.

向後兼容
因爲大的版本升級本身就充滿挑戰, 因此我們盡力不讓在在升級ElasticSearch過程中更新你的mapping字義. 首先, string字段可以繼續在已定義的2.x版本的索引中繼續使用, 而當創建新的索引時, ElasticSearch會做些處理以自動把string映射成等價的text或keyword. 如果在你已有的索引模板(index template)中定義有string字段, 這一點將非常有用, 因爲這些模板無須改動即可使用到ElasticSearch 5.x中. 話說回來, 你還是需要着手做這些模板做些升級, 因爲在ElasticSearch 6.0中我們可能會移除這個向後兼容的邏輯.

如在5.x版本中創建如下mapping:
在這裏插入圖片描述
index下面有三個選項:

"index": "no"   #不分詞,不索引
"index": "analyze"    #分詞,索引
"index": "not_analyzed" # 不去分詞

查看mapping:
在這裏插入圖片描述
或java:

startObject("url").field("index", "not_analyzed").field("type", "string").field("store", "yes").endObject()

查看mapping:

          "url": {
            "type": "keyword",
            "store": true
          }

參考:https://segmentfault.com/a/1190000008897731
 

五、elasticsearch 中的 ignore_above

在業務系統中,遇到過兩個問題:
問題1:設置爲keyword類型的字段,插入很長的大段內容後,報字符超出異常,無法插入。
問題2:檢索超過ignore_above設定長度的字段後,無法返回結果。

對超過 ignore_above 的字符串,analyzer 不會進行處理;所以就不會索引起來。導致的結果就是最終搜索引擎搜索不到了。這個選項主要對 not_analyzed 字段(5.x版本其實就是type類型爲keyword的字段)有用,這些字段通常用來進行過濾、聚合和排序。而且這些字段都是結構化的,所以一般不會允許在這些字段中索引過長的項。

PUT my_index
{
  "mappings": {
    "my_type": {
      "properties": {
        "message": {
          "type": "string",
          "index": "not_analyzed",
          "ignore_above": 20
        }
      }
    }
  }
}

PUT my_index/my_type/1
{
  "message": "Syntax error"
}

PUT my_index/my_type/2
{
  "message": "Syntax error with some long stacktrace"
}

GET _search
{
  "aggs": {
    "messages": {
      "terms": {
        "field": "message"
      }
    }
  }
}

搜索結果:
{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 2,
    "max_score": 1,
    "hits": [
      {
        "_index": "my_index",
        "_type": "my_type",
        "_id": "2",
        "_score": 1,
        "_source": {
          "message": "Syntax error with some long stacktrace"
        }
      },
      {
        "_index": "my_index",
        "_type": "my_type",
        "_id": "1",
        "_score": 1,
        "_source": {
          "message": "Syntax error"
        }
      }
    ]
  },
  "aggregations": {
    "messages": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": "Syntax error",
          "doc_count": 1
        }
      ]
    }
  }
}

(1) 這個字段忽略所有長度超過 20 的字符串
(2) 這個文檔會被成功索引
(3) 這個文檔會被索引,但是 message 字段卻不會被索引
(4) 搜索會返回這兩個問答是哪個,但是隻有第一個會出現在項的聚合中

ignore_aboe 設置允許針對統一索引中的同樣名稱的字段設置不同的值。可以使用 PUT mapping API來更新已經存在的字段。

這個選項在保護 Lucene 的項的字節長度限制 32766 發揮作用。
如果超過32766則會報異常IllegalArgumentException:Document contains at least one immense term in field="message" (whose UTF8 encoding is longer than the max length 32766), all of which were skipped.

ignore_above 默認值是256,該參數的意思是,當字段文本的長度大於指定值時,不做倒排索引。
ignore_above 最大值是32766,但是要根據場景來設置,比如說中文最大值應該是設定在10922。

Elasticsearch中採用的是字符個數來定義igmore_above值, 而lucene是採用byte字節;那麼每個象形文字在utf-8中佔位是3,每個Literal字符在utf-8中佔位是2, 每個ASCII字符在utf-8中佔位是1.
象形文字字符(中文、韓文、日文): 10922 個字符(算法是: 32766 / 3).
Literal字符(印度文、俄文): 16383 個字符(算法是: 32766 / 2).
ASCII字符(a-zA-Z0-9以及~!@#$等特殊字符): 32766個字符(算法是: 32766).

參考:
https://www.elastic.co/guide/en/elasticsearch/reference/current/ignore-above.html
https://www.jianshu.com/p/133a0f49311a
 

六、maven中引入的Elasticsearch版本引發的問題
		<dependency>
			<groupId>org.elasticsearch.client</groupId>
			<artifactId>x-pack-transport</artifactId>
			<version>5.3.3</version>
		</dependency>
		<dependency>
			<groupId>org.elasticsearch</groupId>
			<artifactId>elasticsearch</artifactId>
			<version>5.3.3</version>
		</dependency>

遇到了個奇怪的問題,就是我們公司用的是阿里Elasticsearch版本是5.5.3,我在maven中引入的版本是5.4.2,在調client的時候有時會報下面的錯,有時卻不會,也是奇了怪了。後來我改爲5.3.3就不會出現該問題

2019-02-12 17:11:00.500 ERROR 25480 --- [nio-8082-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is NoNodeAvailableException[None of the configured nodes are available: [{#transport#-1}{qRGG2D_ABCaB8JPk79Jabc}{es-cn-v00000002000ab2vp.elasticsearch.aliyuncs.com}{192.168.0.1:9300}]]] with root cause

org.elasticsearch.client.transport.NoNodeAvailableException: None of the configured nodes are available: [{#transport#-1}{qRGG2D_ABCaB8JPk79Jabc}{es-cn-v00000002000ab2vp.elasticsearch.aliyuncs.com}{192.168.0.104:9300}]
        at org.elasticsearch.client.transport.TransportClientNodesService.ensureNodesAreAvailable(TransportClientNodesService.java:348) ~[elasticsearch-5.4.2.jar!/:5.4.2]
        at org.elasticsearch.client.transport.TransportClientNodesService.execute(TransportClientNodesService.java:246) ~[elasticsearch-5.4.2.jar!/:5.4.2]
        at org.elasticsearch.client.transport.TransportProxyClient.execute(TransportProxyClient.java:59) ~[elasticsearch-5.4.2.jar!/:5.4.2]
        at org.elasticsearch.client.transport.TransportClient.doExecute(TransportClient.java:366) ~[elasticsearch-5.4.2.jar!/:5.4.2]
        at org.elasticsearch.client.support.AbstractClient.execute(AbstractClient.java:408) ~[elasticsearch-5.4.2.jar!/:5.4.2]
        at org.elasticsearch.client.support.AbstractClient$IndicesAdmin.execute(AbstractClient.java:1256) ~[elasticsearch-5.4.2.jar!/:5.4.2]
        at org.elasticsearch.action.ActionRequestBuilder.execute(ActionRequestBuilder.java:80) ~[elasticsearch-5.4.2.jar!/:5.4.2]
        at org.elasticsearch.action.ActionRequestBuilder.execute(ActionRequestBuilder.java:54) ~[elasticsearch-5.4.2.jar!/:5.4.2]
        at com.automatic.dao.PublicSafetySearchDaoImpl.indexs(PublicSafetySearchDaoImpl.java:683) ~[AutomaticEsIndex.jar!/:0.0.1-SNAPSHOT]
        at com.automatic.controller.IndexController.xiao(IndexController.java:38) ~[AutomaticEsIndex.jar!/:0.0.1-SNAPSHOT]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_131]
。。。。。。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章