解决 SpringBoot 整合 Elasticsearch 报错:Set fielddata=true on [xxxx] in order to load fielddata in......
文章目录一、问题描述二、解决方法一、问题描述使用 SpringBoot 整合 Elasticsearch 时,运行程序,报错:二、解决方法 出现这种情况,是因为修改了代码,而在进行搜索后,没有将 ESClient 进行重启,这样,再一次进行搜索的时候,使用的还是同一个 ESClient,就会导致重复的聚合名称出现。 &
一、问题描述
使用 SpringBoot 整合 Elasticsearch ,实现分组查询,本来程序运行得好好的,抽取出部分代码后,突然报错(真的是突然,并没有改变逻辑,只是抽取代码出来)。
控制台打印的日志里的关键信息是这样的:
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed;
nested exception is Failed to execute phase [dfs], all shards failed; shardFailures {[9jF_AW-9TfqyX3gVtGpGTQ][skuinfo][0]:
RemoteTransportException[[9jF_AW-][172.17.0.6:9300][indices:data/read/search[phase/dfs]]]; nested: IllegalArgumentException[Fielddata is disabled on text fields by default. Set fielddata=true on [categoryName] 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.]; }{[9jF_AW-9TfqyX3gVtGpGTQ][skuinfo][1]: RemoteTransportException[[9jF_AW-][172.17.0.6:9300][indices:data/read/search[phase/dfs]]]; nested: IllegalArgumentException[Fielddata is disabled on text fields by default. Set fielddata=true on [categoryName] 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.]; }{[9jF_AW-9TfqyX3gVtGpGTQ][skuinfo][2]:
… …
它是说,需要将映射到 Elasticsearch 索引库中的类的属性 categoryName 设置为 fielddate=true,以便通过反转索引,在内存中加载 fielddata 域数据。但是这可能会占用大量内存。或者使用关键字字段代替。
二、解决方法
我先在代码中进行了设置:
但是并没有在 Elasticsearch 中生效😥,还是报这个错误,还是要去 Elasticsearch 中直接设置的,使用 kibana 执行 DSL 语句:
我的代码是这样的:
public Map<String, Object> search(Map<String, String> searchMap) {
// 搜索条件构建对象
NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
AggregatedPage<SkuInfo> page = elasticsearchTemplate.queryForPage(
builder.build(), SkuInfo.class);
// 添加聚合操作
builder.addAggregation(AggregationBuilders.terms("skuCategory").field("categoryName"));
AggregatedPage<SkuInfo> page1 = elasticsearchTemplate.queryForPage(
builder.build(), SkuInfo.class);
StringTerms stringTerms = page1.getAggregations().get("skuCategory");
List<String> categoryList=new ArrayList<>();
for(StringTerms.Bucket bucket:stringTerms.getBuckets()){
String categoryName=bucket.getKeyAsString();
categoryList.add(categoryName);
}
Map<String, Object> resultMap = new HashMap<String, Object>();
resultMap.put("categoryList",categoryList);
return resultMap;
}
主要是根据 categoryName 进行分组,把 categoryName 索引集中的数据都取出来,运行结果:
夸了个大张,错误解决了,但是它居然进行了分词,这样分成一个字一个字的形式,并不是我要的效果。
刚刚报错的地方有一句 “Alternatively use a keyword field instead.”,再看看此时的索引信息,执行 GET /skuinfo/_mapping
:
可以看到,它是有 field 的,而且是 keyword 类型的,我们就按照报错信息提示的,用 keyword 进行替代:
builder.addAggregation(AggregationBuilders.terms("skuCategory").field("categoryName.keyword"));
运行结果:
既然用了 keyword,那么应该也就不需要把 fileddata 设置为 true 了,因为报错信息里也说了,这样会占用大量内存:
PUT skuinfo/_mapping/docs
{
"properties": {
"categoryName": {
"type": "text"
}
}
}
再执行程序,查询出来的是没有分词的结果。
这时,又发现了一个奇怪的现象,在代码里明明是把 categoryName 设置成 keyword 类型的,但是在 Elasticsearch 里,看到它却是 text 类型,而且有 keyword 域,我们只能通过手动选择 keyword 进行查询。
对于 keyword 类型,在存储数据时候,是不会分词的,而 text 类型,在建立索引存储数据时候,会自动分词,并生成索引(这是很智能的,但在有些字段里面是没用的,所以对于有些字段使用 text 则浪费了空间)。
后来,我删除了 skuinfo 这个索引,重新向索引库导入了数据,发现 categoryName 域又变成了:
猜测出现这种现象的愿意可能是 Elasticsearch 会对索引类型进行动态映射,所以手动把 text 类型的动态映射关闭掉:
PUT /索引名/索引类型/_mapping
{
"dynamic":false
}
这样的话,域的类型应该就是 text 不变了。
更多推荐
所有评论(0)