SpringBoot2整合ElasticSearch(包含ElasticSearch入门+spring-boot-starter-data-elasticsearch)

前言

作为互联网热点知识的ElasticSearch,怎能不学。如果你有空余时间,欢迎入门;如果你没空余时间,也欢迎走马观花看一眼。走过如果不要错过,这是一篇自我感觉相对对入门者来说比较全面的文章了,希望对大家有帮助,有什么疑问或者建议欢迎留言讨论。

Why&What Elasticsearch?

  • 概念Elasticsearch 是一个开源分布式高扩展高实时的RESTful 搜索和分析引擎,基于Lucene
  • 背景Elasticsearch是与名为Logstash的数据收集和日志解析引擎以及名为Kibana的分析和可视化平台一起开发的。这三个产品被设计成一个集成解决方案,称为“Elastic Stack”(以前称为“ELK stack”)。
  • 价值Elasticsearch能很方便的使大量数据具有搜索分析探索的能力,能使数据在生产环境变得更有价值
  • 步骤:首先用户将数据提交到Elastic Search 数据库中,再通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据,当用户搜索数据时候,再根据权重将结果排名打分,再将返回结果呈现给用户。
  • 谁在用: 1. Wikipedia 使用 Elasticsearch 提供带有高亮片段的全文搜索,还有 search-as-you-type 和 did-you-mean 的建议。2. Stack Overflow 将地理位置查询融入全文检索中去,并且使用 more-like-this 接口去查找相关的问题和回答。3. GitHub 使用 Elasticsearch 对1300亿行代码进行查询。
  • 端口9200http协议的RESTful接口。9300tcp通讯端口,集群间和TCPClient都走的它。

ElasticSearch&DB的区别

DBES
`database`数据库`index`索引
`table`表`type`类型
`row`行(一条数据)`document`文档
`column`列(字段名)`field`字段

Download&Install Elasticsearch

  1. https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.8.1.zip下载6.8.1版本 如果从官网https://www.elastic.co/cn/downloads/elasticsearch下载Elasticsearch,下载到的版本太新,客户端不支持
  2. 运行bin\elasticsearch.bat
  3. 访问http://127.0.0.1:9200/ ,见到以下返回信息(目前推荐ES6.8.1的版本,比较靠谱,minimum_index_compatibility_version=5.X的,最新版ES7最低的client版本是6.X,会有兼容问题,请看末尾版本兼容问题部分)
{
    "name": "sUR4zrr",
    "cluster_name": "elasticsearch",
    "cluster_uuid": "ODsZw-P1QMe9CDeOqEQQvA",
    "version": {
        "number": "6.7.1",
        "build_flavor": "default",
        "build_type": "zip",
        "build_hash": "2f32220",
        "build_date": "2019-04-02T15:59:27.961366Z",
        "build_snapshot": false,
        "lucene_version": "7.7.0",
        "minimum_wire_compatibility_version": "5.6.0",
        "minimum_index_compatibility_version": "5.0.0"
    },
    "tagline": "You Know, for Search"
}
  1. 下载Chrome插件 elasticsearch-head https://www.chromefor.com/elasticsearch-head_v0-1-4/dejavu-elasticsearch-web-ui https://www.chromefor.com/dejavu-elasticsearch-web-ui_v3-4-0/

ElasticSearch 倒排索引(Inverted Index)| 什么是倒排索引?

篇幅较长,请看 https://blog.csdn.net/moshowgame/article/details/99413448

ElasticSearch之analyzer分词器+ICU分词插件

篇幅较长,请看 https://zhengkai.blog.csdn.net/article/details/99448661

Elasticsearch REST API

这里补充几个常用的API,以便大家对ES的REST API有简单的了解:

  1. curl -X PUT \ http://localhost:9200/blog ,PUT请求,后面的blog是要新建的index,也就是这个api相当于新建一个数据库
  2. curl -X POST \ http://localhost:9200/blog/article \ -d ' { "author": "zhengkai.blog.csdn.net", "createtime": 1563689639575, "id": 2, "text": "Elasticsearch是一个开源的分布式、高扩展、高实时的RESTful 搜索和分析引擎,基于Lucene......", "title": "SpringBoot整合ElasticSearch" }' ,POST请求,如果不存在叫article的type类型/table表,则新增,并插入记录。
  3. curl -X GET \ 'http://localhost:9200/article_info/doc/61969/_termvectors?fields=title' 格式为/${index}/${type}/${id}/_termvectors?fields=${fields_name} ,GET请求,查询分词结果。返回的JSON中term_vectors.field.terms里面就是分词结果。
  4. curl -X POST \http://localhost:9200/_search -d '{"query":{"bool":{"must":[{"wildcard":{"title.keyword":{"wildcard":"*SpringBoot*","boost":1}}}],"disable_coord":false,"adjust_pure_negative":true,"boost":1}}}' ,POST请求,进行搜索。

2019.7.23 补充。这个查询情况比较复杂,补充一些**【ElasticSearch分词和查询相关】**东西:

  • 情况一:{"query":{"wildcard": { "title": "*springboot*" }}} 可以查询到包含SpringBoot和springboot忽略大小写的标题,走分词,所以只能用小写查。而{"query":{"wildcard": { "title": "*SpringBoot*" }}}什么都查询不出来。。。
  • 情况二:{"query":{"wildcard": { "title.keyword": "*SpringBoot*" }}} 可以查询到包含SpringBoot的大小写必须一致的标题,不走分词。而{"query":{"wildcard": { "title.keyword": "*springboot*" }}} `什么都查询不出来。。。
  • 情况三:{"query":{"match": { "title": "bootelasticsearch" }}},可以查询出来,而且无论bootelasticsearch中什么字母是大写或者小写,忽略大小写。。。
  • 情况四:{"query":{"term": { "title": "bootelasticsearch" }}},可以查询出来,且必须小写字母才能查询出来,其他都不行。。。

以上情况很奇怪对吧,为什么呢,请看下文分解。。

  • bool(boolQuery)和must(boolQuery.must)的关系,就像sql的whereand一样,作为条件连接的桥梁来使用,多个条件的话,就使用多个must。
  • wildcard模糊查询,跟SQL的LIKE查询很类似,条件"*SpringBoot*"表示包含SpringBoot的文本。
  • wildcard的情况下,查询字段是text类型的话(es5以后没有string类型呢,分text和keyword,string数据put到es5中,默认是text。),直接title查询是走分词的,例如查询springboot,将会查询到Spring;用title.keyword的话这样可以不走分词,进行精准匹配。
  • es默认分词器为standard analyzer,大写字母全部转为了小写字母,并存入了倒排索引以供搜索。”SpringBootElasticSearch”会被分解成[bootelasticsearch]写入倒排索引(使用3的分词结果接口可以看到。坑啊!不是应[该spring,boot,elasticsearch]吗!!!)。 所以term query 查询的是倒排索引中确切的term,必须要匹配到大写的BootElasticSearch;而match query 会对filed进行分词操作,然后在查询,忽略大小写

布尔过滤器bool query

一个 bool 过滤器由三部分组成:

{
   "bool" : {
      "must" :     [],
      "should" :   [],
      "must_not" : [],
   }
}
  • must 所有的语句都 必须(must) 匹配,与 AND 等价。
  • must_not 所有的语句都 不能(must not) 匹配,与 NOT 等价。
  • should 至少有一个语句要匹配,与 OR 等价。

下面是一个简单明了的SQL->Elasticsearch QL

SELECT product
FROM   products
WHERE  (price = 20 OR productID = "MOSHOW IN ACTION-#fJ3")
  AND  (price != 30)

用es写就是:

{
   "query" : {
      "filtered" : { 
         "filter" : {
            "bool" : {
              "should" : [
                 { "term" : {"price" : 20}}, 
                 { "term" : {"productID" : "MOSHOW IN ACTION-#fJ3"}} 
              ],
              "must_not" : {
                 "term" : {"price" : 30} 
              }
           }
         }
      }
   }
}

匹配查询 match query

匹配查询 match 是个 核心 查询。无论需要查询什么字段, match 查询都应该会是首选的查询方式。 它是一个高级全文查询 ,这表示它既能处理全文字段,又能处理精确字段。

{
    "query": {
        "match": {
            "title": "QUICK!"
        }
    }
}

执行上面这个 match 查询的步骤是:

  1. 检查字段类型 。标题 title 字段是一个 string 类型( analyzed )已分析的全文字段,这意味着查询字符串本身也应该被分析。
  2. 分析查询字符串 。将查询的字符串 QUICK! 传入标准分析器中,输出的结果是单个项 quick 。因为只有一个单词项,所以 match 查询执行的是单个底层 term 查询(查询小写的quick)。
  3. 查找匹配文档 。用 term 查询在倒排索引中查找 quick 然后获取一组包含该项的文档,例如结果是文档包含“The quick brown fox”/“The quick brown fox jumps over the quick dog”/“The quick brown fox jumps over the lazy dog”,以上三个都会被查询出来。
  4. 为每个文档评分 。用 term 查询计算每个文档相关度评分 _score ,这是种将 词频(term frequency,即词 quick 在相关文档的 title 字段中出现的频率)和反向文档频率(inverse document frequency,即词 quick 在所有文档的 title 字段中出现的频率),以及字段的长度(即字段越短相关度越高)相结合的计算方式。

wildcard 通配符与regexp正则表达式查询

与 prefix 前缀查询的特性类似, wildcard 通配符查询也是一种底层基于词的查询, 与前缀查询不同的是它允许指定匹配的正则式。它使用标准的 shell 通配符查询: ? 匹配任意字符, * 匹配 0 或多个字符
这个查询会匹配例如包含 W1F 7HWW2F 8HW 的文档:

{
    "query": {
        "wildcard": {
            "postcode": "W?F*HW" 
        }
    }
}

这个查询会匹配邮政编码:

{
    "query": {
        "regexp": {
            "postcode": "W[0-9].+" 
        }
    }
}

查询精确值term query

term 查询对于查找单个值非常有用,但通常我们可能想搜索多个值。 如果我们想要查找价格字段值为 $20 或 $30 的文档该如何处理呢?

SELECT product
FROM   products
WHERE  (price = 20 OR price = 30)

不需要使用多个 term 查询,我们只要用单个 terms 查询(注意末尾的 s ), terms 查询好比是 term 查询的复数形式(以英语名词的单复数做比)。

它几乎与 term 的使用方式一模一样,与指定单个价格不同,我们只要将 term 字段的值改为数组即可。另外,与 term 查询一样,也需要将其置入 filter 语句的constant_score常量评分查询中使用:

{
    "query" : {
        "constant_score" : {
            "filter" : {
                "terms" : { 
                    "price" : [20, 30]
                }
            }
        }
    }
}

范围查询range query

range 查询可同时提供包含(inclusive)和不包含(exclusive)这两种范围表达式,可供组合的选项如下:

gt: > 大于(greater than)
lt: < 小于(less than)
gte: >= 大于或等于(greater than or equal to)
lte: <= 小于或等于(less than or equal to)
SELECT document
FROM   products
WHERE  price BETWEEN 20 AND 40
{
    "query" : {
        "constant_score" : {
            "filter" : {
                "range" : {
                    "price" : {
                        "gte" : 20,
                        "lt"  : 40
                    }
                }
            }
        }
    }
}

项目实战


前面都是基础,下面才是开始Coding。

开源项目

项目源码已经上传到github,有需要可以参考或者下载使用。

Maven依赖

	<dependencies>
		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
        </dependency>
    </dependencies>

Application配置

这里是application.yml的配置

server:
  port: 9999
  servlet:
      context-path: /es
tomcat:
    remote-ip-header: x-forward-for
    uri-encoding: UTF-8
    max-threads: 10
    background-processor-delay: 30
spring:
    http:
      encoding:
        force: true
        charset: UTF-8
    application:
        name: spring-cloud-study-security-elasticsearch
        author: zhengkai.blog.csdn.net
    data:
        elasticsearch:
          cluster-nodes: 127.0.0.1:9300
          cluster-name: elasticsearch

Entity实体

import java.util.Date;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import lombok.Data;

@Data
@Document(indexName = "article_info", type = "doc")
public class Article {
	@Id
    private Integer id;

    private String title;

    private String text;

    private Date createtime;

    private String author;

}

ElasticsearchRepository

ArticleRepository 接口继承ElasticsearchRepository来完成基本的CRUD分页操作的,功能强大并且和普通JPA没有什么区别。保存的话直接用save就可以了,以下是search相关的方法:

  • Iterable search(QueryBuilder query);
  • Page search(QueryBuilder query, Pageable pageable);
  • Page search(SearchQuery searchQuery);
  • Page searchSimilar(T entity, String[] fields, Pageable pageable);
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;
/**
 * ElasticsearchRepository --> ElasticsearchCrudRepository --> PagingAndSortingRepository --> CrudRepository
 * @author zhengkai.blog.csdn.net
 */
@Repository
public interface ArticleRepository extends ElasticsearchRepository<Article, Integer> {

}

RestController

import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.web.PageableDefault;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.softdev.system.demo.entity.Article;
import com.softdev.system.demo.repository.ArticleRepository;
import com.softdev.system.demo.util.ApiReturnUtil;

import cn.hutool.core.util.RandomUtil;
/**
 *  ElasticSearch控制器
 * @author  zhengkai.blog.csdn.net
 * */
@RestController
public class ArticleController {

	@Autowired
	private ElasticsearchTemplate elasticsearchTemplate;
	
	@Autowired
	private ArticleRepository articleRepository;

	@GetMapping("new")
	public Object newArticle(@RequestParam(defaultValue = "SpringBootElasticSearch") String title, @RequestParam(defaultValue = "`Elasticsearch` 是一个`开源`的`分布式`、`高扩展`、`高实时`的RESTful `搜索和分析引擎`,基于`Lucene`......") String text){
		//构建并保存Article
		Article article = new Article();
		article.setId(RandomUtil.randomInt(10000,99999));
		article.setTitle(title);
		article.setText(text);
		article.setCreatetime(new Date());
		article.setAuthor("zhengkai.blog.csdn.net");
		return ApiReturnUtil.success(article);
	}

	@GetMapping("save")
	public Object save(@RequestParam(defaultValue = "SpringBootElasticSearch") String title, @RequestParam(defaultValue = "`Elasticsearch` 是一个`开源`的`分布式`、`高扩展`、`高实时`的RESTful `搜索和分析引擎`,基于`Lucene`......") String text){
		//构建并保存Article
		Article article = new Article();
		article.setId(RandomUtil.randomInt(10000,99999));
		article.setTitle(title);
		article.setText(text);
		article.setCreatetime(new Date());
		article.setAuthor("zhengkai.blog.csdn.net");
		articleRepository.save(article);
		return ApiReturnUtil.success(article);
	}

	/**
	 * ElasticSearch之Search封装查询
	 * @author  zhengkai.blog.csdn.net
	 * @param title   搜索标题
	 * @param pageable page = 第几页参数(第一页是0), value = 每页显示条数
	 */
	@GetMapping("search")
	public Object search(@RequestParam(defaultValue = "SpringBoot") String title, @PageableDefault(page = 0, value = 10) Pageable pageable){
		//以下查询等同于封装了{"query":{"bool":{"must":[{"wildcard":{"title.keyword":{"wildcard":"*SpringBoot*","boost":1}}}],"disable_coord":false,"adjust_pure_negative":true,"boost":1}}}
		//按标题进行模糊查询
		QueryBuilder queryBuilder = QueryBuilders.wildcardQuery("title.keyword", "*SpringBoot*");
		//按照顺序构建builder,bool->must->wildcard ,有了上文的JSON,顺序就很好理解了
		BoolQueryBuilder must = QueryBuilders.boolQuery().must(queryBuilder);
		//封装pageable分页
		Page<Article> queryResult =  articleRepository.search(must,pageable);
		//返回
		return ApiReturnUtil.success(queryResult.getContent());
	}
	/**
	 * ElasticSearch之elasticsearchTemplate查询
	 * @author  zhengkai.blog.csdn.net
	 * @param title   搜索标题
	 */
	@GetMapping("originSearch")
	public Object originSearch(@RequestParam(defaultValue = "SpringBoot") String title) {
		BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
		QueryBuilder queryBuilder = QueryBuilders.wildcardQuery("title.keyword", "*SpringBoot*");
		BoolQueryBuilder must = boolQuery.must(queryBuilder);
		NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
		NativeSearchQuery build = nativeSearchQueryBuilder.withQuery(must).build();
		List<Article> queryForList = elasticsearchTemplate.queryForList(build, Article.class);
		
		return ApiReturnUtil.success(queryForList);
	}
}

Result效果演示

  1. 连续调用6次左右,http://localhost:9999/es/save进行保存(如果你想用API保存,可以http://localhost:9999/es/new访问,得到一些JSON数据)
  2. 调用一次http://localhost:9999/es/save?title=ElasticSearch保存一条title不包含SpringBoot的数据(下文根据SpringBoot来检索)
  3. 打开浏览器ElasticSearch HeadDejavu UI插件进行查看(前提是安装好插件!!!否则请跳过。。。)
  • chrome-extension://ffmkiejjmecolpfloofpjologoblkegm/elasticsearch-head/index.html
  • chrome-extension://jopjeaiilkcibeohjdmejhoifenbnmlh/index.html?appname=article_info&url=http://localhost:9200&mode=edit在这里插入图片描述
  1. 在Header插件的Structured Query界面中选择 must+doc.title.keyword+wildcard+*SpringBoot*的查询条件,成功查询到数据。在这里插入图片描述
    5.访问http://localhost:9999/es/search
    在这里插入图片描述

或者用ES的RESTful API ,POST以下链接:

http://localhost:9200/_search
{“query”:{“bool”:{“must”:[{“wildcard”:{“title.keyword”:{“wildcard”:“SpringBoot”,“boost”:1}}}],“disable_coord”:false,“adjust_pure_negative”:true,“boost”:1}}}

es返回结果json解析:

  • took:整个搜索请求花费了多少毫秒
  • hits.total:本次搜索,返回了几条结果
  • hits.max_score:本次搜索的所有结果中,最大的相关度分数是多少,每一条document对于search的相关度,越相关,_score分数越大,排位越靠前
  • hits.hits:默认查询前10条数据,完整数据,_score降序排序
  • shards:shards fail的条件(primary和replica全部挂掉),不影响其他shard。默认情况下来说,一个搜索请求,会打到一个index的所有primary shard上去,当然了,每个primary shard都可能会有一个或多个replic shard,所以请求也可以到primary shard的其中一个replica shard上去。
  • timeout:默认无timeout,latency平衡completeness,手动指定timeout,timeout查询执行机制,格式:timeout=10ms,timeout=1s,timeout=1mGET /_search?timeout=10m
    在这里插入图片描述

杩滅▼涓绘満寮鸿揩鍏抽棴浜嗕竴涓幇鏈夌殑杩炴帴銆?

这个报错转换过来就是:远程主机强迫关闭了一个现有的连接

exception caught on transport layer [Netty4TcpChannel{localAddress=/127.0.0.1:9300, remoteAddress=/127.0.0.1:53494}], closing connection
java.io.IOException: 杩滅▼涓绘満寮鸿揩鍏抽棴浜嗕竴涓幇鏈夌殑杩炴帴銆?
        at sun.nio.ch.SocketDispatcher.read0(Native Method) ~[?:?]
        at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:43) ~[?:?]
        at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:276) ~[?:?]
        at sun.nio.ch.IOUtil.read(IOUtil.java:245) ~[?:?]
        at sun.nio.ch.IOUtil.read(IOUtil.java:223) ~[?:?]
        at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:358) ~[?:?]
        at io.netty.buffer.PooledHeapByteBuf.setBytes(PooledHeapByteBuf.java:261) ~[netty-buffer-4.1.32.Final.jar:4.1.32.Final]
        at io.netty.buffer.AbstractByteBuf.writeBytes(AbstractByteBuf.java:1132) ~[netty-buffer-4.1.32.Final.jar:4.1.32.Final]
        at io.netty.channel.socket.nio.NioSocketChannel.doReadBytes(NioSocketChannel.java:347) ~[netty-transport-4.1.32.Final.jar:4.1.32.Final]
        at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:148) [netty-transport-4.1.32.Final.jar:4.1.32.Final]
        at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:656) [netty-transport-4.1.32.Final.jar:4.1.32.Final]
        at io.netty.channel.nio.NioEventLoop.processSelectedKeysPlain(NioEventLoop.java:556) [netty-transport-4.1.32.Final.jar:4.1.32.Final]
        at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:510) [netty-transport-4.1.32.Final.jar:4.1.32.Final]
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:470) [netty-transport-4.1.32.Final.jar:4.1.32.Final]
        at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:909) [netty-common-4.1.32.Final.jar:4.1.32.Final]
        at java.lang.Thread.run(Thread.java:834) [?:?]

版本兼容问题

minimum_index_compatibility_version这里定义的最低版本会受spring-boot-starter-data-elasticsearch的版本影响。

所以目前推荐ES6,6.8.1左右的版本,比较靠谱。我一开始就是到官网下载最新版本,就被坑了。

如果你看到JAVA控制台有以下错误,基本就是版本兼容性问题了,直接访问localhost:9200获取版本信息。

org.elasticsearch.client.transport.NoNodeAvailableException: None of the configured nodes are available

推断错误的话。可以从一下日志查找思路,特别是看ES控制台输出的内容,可以清楚的看到

closing connection
java.lang.IllegalStateException: Received handshake message from unsupported version: [5.0.0] minimal compatible version is: [6.8.0]

{
  "name" : "WORKPC-MOSHOW",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "fDlrxuUcTjqgvfpWbl3Hcg",
  "version" : {
    "number" : "7.2.0",
    "build_flavor" : "default",
    "build_type" : "zip",
    "build_hash" : "508c38a",
    "build_date" : "2019-06-20T15:54:18.811730Z",
    "build_snapshot" : false,
    "lucene_version" : "8.0.0",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}
[/es] threw exception [Request processing failed; nested exception is NoNodeAvailableException[None of the configured nodes are available: [{#transport#-1}{mQ1hg9-tT3mvRnfLIAaZHg}{127.0.0.1}{127.0.0.1:9300}]]] with root cause

org.elasticsearch.client.transport.NoNodeAvailableException: None of the configured nodes are available: [{#transport#-1}{mQ1hg9-tT3mvRnfLIAaZHg}{127.0.0.1}{127.0.0.1:9300}]
	at org.elasticsearch.client.transport.TransportClientNodesService.ensureNodesAreAvailable(TransportClientNodesService.java:347) ~[elasticsearch-5.6.11.jar:5.6.11]
	at org.elasticsearch.client.transport.TransportClientNodesService.execute(TransportClientNodesService.java:245) ~[elasticsearch-5.6.11.jar:5.6.11]
	at org.elasticsearch.client.transport.TransportProxyClient.execute(TransportProxyClient.java:59) ~[elasticsearch-5.6.11.jar:5.6.11]
	at org.elasticsearch.client.transport.TransportClient.doExecute(TransportClient.java:366) ~[elasticsearch-5.6.11.jar:5.6.11]
	at org.elasticsearch.client.support.AbstractClient.execute(AbstractClient.java:408) ~[elasticsearch-5.6.11.jar:5.6.11]
	at org.elasticsearch.action.ActionRequestBuilder.execute(ActionRequestBuilder.java:80) ~[elasticsearch-5.6.11.jar:5.6.11]
	at org.elasticsearch.action.ActionRequestBuilder.execute(ActionRequestBuilder.java:54) ~[elasticsearch-5.6.11.jar:5.6.11]
	at org.springframework.data.elasticsearch.core.ElasticsearchTemplate.index(ElasticsearchTemplate.java:571) ~[spring-data-elasticsearch-3.0.10.RELEASE.jar:3.0.10.RELEASE]
	at org.springframework.data.elasticsearch.repository.support.AbstractElasticsearchRepository.save(AbstractElasticsearchRepository.java:156) ~[spring-data-elasticsearch-3.0.10.RELEASE.jar:3.0.10.RELEASE]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.__invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:45009) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:45012) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Method.java:564) ~[na:na]
	at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:377) ~[spring-data-commons-2.0.10.RELEASE.jar:2.0.10.RELEASE]
	at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:200) ~[spring-data-commons-2.0.10.RELEASE.jar:2.0.10.RELEASE]
	at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:641) ~[spring-data-commons-2.0.10.RELEASE.jar:2.0.10.RELEASE]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:605) ~[spring-data-commons-2.0.10.RELEASE.jar:2.0.10.RELEASE]
	at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:590) ~[spring-data-commons-2.0.10.RELEASE.jar:2.0.10.RELEASE]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59) ~[spring-data-commons-2.0.10.RELEASE.jar:2.0.10.RELEASE]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) ~[spring-aop-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61) ~[spring-data-commons-2.0.10.RELEASE.jar:2.0.10.RELEASE]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at com.sun.proxy.$Proxy88.save(Unknown Source) ~[na:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.__invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:45009) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:45012) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Method.java:564) ~[na:na]
	at org.zeroturnaround.javarebel.integration.util.ReloadingProxyFactory$ReloadingMethodHandler.invoke(SourceFile:74) ~[na:201907051008]
	at com.sun.proxy.$Proxy88.save(Unknown Source) ~[na:na]
	at com.softdev.system.demo.controller.ArticleController.save(ArticleController.java:38) ~[classes/:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.__invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:45009) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:45012) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Method.java:564) ~[na:na]
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:209) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) ~[spring-webmvc-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:891) ~[spring-webmvc-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) ~[spring-webmvc-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991) ~[spring-webmvc-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925) ~[spring-webmvc-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:974) ~[spring-webmvc-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:866) ~[spring-webmvc-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:635) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:851) ~[spring-webmvc-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-embed-websocket-8.5.34.jar:8.5.34]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:109) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.catalina.core.StandardContextValve.__invoke(StandardContextValve.java:96) [tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:41002) [tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:493) [tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81) [tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) [tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:800) [tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:806) [tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1498) [tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.34.jar:8.5.34]
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1135) [na:na]
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) [na:na]
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.34.jar:8.5.34]
	at java.base/java.lang.Thread.run(Thread.java:844) [na:na]
[WARN ][o.e.t.TcpTransport       ] [WORKPC-MOSHOW] exception caught on transport layer [Netty4TcpChannel{localAddress=/127.0.0.1:9300, remoteAddress=/127.0.0.1:64883}], closing connection
java.lang.IllegalStateException: Received handshake message from unsupported version: [5.0.0] minimal compatible version is: [6.8.0]
        at org.elasticsearch.transport.InboundMessage.ensureVersionCompatibility(InboundMessage.java:137) ~[elasticsearch-7.2.0.jar:7.2.0]
        at org.elasticsearch.transport.InboundMessage.access$000(InboundMessage.java:39) ~[elasticsearch-7.2.0.jar:7.2.0]
        at org.elasticsearch.transport.InboundMessage$Reader.deserialize(InboundMessage.java:76) ~[elasticsearch-7.2.0.jar:7.2.0]
        at org.elasticsearch.transport.InboundHandler.messageReceived(InboundHandler.java:116) ~[elasticsearch-7.2.0.jar:7.2.0]
        at org.elasticsearch.transport.InboundHandler.inboundMessage(InboundHandler.java:105) ~[elasticsearch-7.2.0.jar:7.2.0]
        at org.elasticsearch.transport.TcpTransport.inboundMessage(TcpTransport.java:660) [elasticsearch-7.2.0.jar:7.2.0]
        at org.elasticsearch.transport.netty4.Netty4MessageChannelHandler.channelRead(Netty4MessageChannelHandler.java:62) [transport-netty4-client-7.2.0.jar:7.2.0]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) [netty-transport-4.1.35.Final.jar:4.1.35.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) [netty-transport-4.1.35.Final.jar:4.1.35.Final]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352) [netty-transport-4.1.35.Final.jar:4.1.35.Final]
        at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:323) [netty-codec-4.1.35.Final.jar:4.1.35.Final]
        at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:297) [netty-codec-4.1.35.Final.jar:4.1.35.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) [netty-transport-4.1.35.Final.jar:4.1.35.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) [netty-transport-4.1.35.Final.jar:4.1.35.Final]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352) [netty-transport-4.1.35.Final.jar:4.1.35.Final]
        at io.netty.handler.logging.LoggingHandler.channelRead(LoggingHandler.java:241) [netty-handler-4.1.35.Final.jar:4.1.35.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) [netty-transport-4.1.35.Final.jar:4.1.35.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) [netty-transport-4.1.35.Final.jar:4.1.35.Final]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352) [netty-transport-4.1.35.Final.jar:4.1.35.Final]
        at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1408) [netty-transport-4.1.35.Final.jar:4.1.35.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) [netty-transport-4.1.35.Final.jar:4.1.35.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) [netty-transport-4.1.35.Final.jar:4.1.35.Final]
        at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:930) [netty-transport-4.1.35.Final.jar:4.1.35.Final]
        at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163) [netty-transport-4.1.35.Final.jar:4.1.35.Final]
        at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:682) [netty-transport-4.1.35.Final.jar:4.1.35.Final]
        at io.netty.channel.nio.NioEventLoop.processSelectedKeysPlain(NioEventLoop.java:582) [netty-transport-4.1.35.Final.jar:4.1.35.Final]
        at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:536) [netty-transport-4.1.35.Final.jar:4.1.35.Final]
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:496) [netty-transport-4.1.35.Final.jar:4.1.35.Final]
        at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:906) [netty-common-4.1.35.Final.jar:4.1.35.Final]
        at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) [netty-common-4.1.35.Final.jar:4.1.35.Final]
        at java.lang.Thread.run(Thread.java:834) [?:?]

补充

2019.8.13补充。es返回结果json解析。
2019.8.12补充。bool query/range query/match query/term query/wildcard&regex query等几个关键查询,更多详情请看官方文档 全文搜索|中文Query DSL|英文

2019.7.23 补充。这个查询情况比较复杂,补充一些**【ElasticSearch分词和查询相关】**东西。

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 博客之星2020 设计师:CY__ 返回首页