Elasticsearch遇到的坑

文章目录

          • 一、内存不够不能启动
          • 二、更新冲突
          • 三、搜索term和terms的区别
          • 四、聚合时提示illegal_argument_exception
          • 五、elasticsearch 中的 ignore_above
          • 六、maven中引入的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:
Elasticsearch遇到的坑_第1张图片
index下面有三个选项:

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

查看mapping:
Elasticsearch遇到的坑_第2张图片
或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版本引发的问题
		
			org.elasticsearch.client
			x-pack-transport
			5.3.3
		
		
			org.elasticsearch
			elasticsearch
			5.3.3
		

遇到了个奇怪的问题,就是我们公司用的是阿里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]
。。。。。。

你可能感兴趣的:(Elasticsearch)