ElasticSearch 入门

本篇为 ElasticSearch 入门学习总结笔记,课程视频地址:ElasticSearch 入门

一、ElasticSearch 简介

1.1、什么是ElasticSearch

​ 简称 ES

  • 基于Apache Lucene 构建的 开源搜索引擎,提供一个分布式多用户能力的全文搜索引擎
  • 采用 JAVA 编写的 ,提供简单易用的 RESTFul API(RESTFul web接口),当前流行的企业级搜索引擎
  • 轻松的 横向扩展,可支持PB级 的结构化或非结构化数据处理
  • 可以准实时地快速存储、搜索、分析海量的数据。(用于云计算中,能够达到实时搜索)

1.2、应用场景

  • 海量数据分析引擎(聚合搜索)
  • 站内搜索引擎
  • 数据仓库

1.3、谁在用ES呢?

英国卫报— 实时分析公众对文章的回应

维基百科、GitHub - 站内实时搜索

百度—实时日志监控平台

阿里、Google、小米、京东....

1.4、环境要求

工具 版本
IDE IDEA或Eclipse
JAVA JDK8
Maven 3.x 以上
NodeJS 6.0以上

二、ElasticSearch 安装

2.1、ES版本问题

  • 版本历史 : 1.x-》2.x-》5.x -》最新6.0
  • 版本选择 : 选择6.0进行演练!

2.2、ES安装-单实例

下载地址:ES Downloads,windows环境下载 ZIP sha ,Linux或者Mac环境下,下载TAR sha

windows 下安装elasticsearch(有访问页面)

ElasticSearch安装部署(Windows)(添加到windows)

2.2.1 单实例的安装(Windows)

1、下载ES zip包

2、安装Jdk8,并查看环境变量配置

3、解压ES包

  • 目录说明:
目录名 说明
config 配置文件
modules 模块存放目录
bin 脚本
lib 第三方库
plugins 第三方插件

4、启动验证服务

​ windows环境在/bin 下载双击 elasticsearch.bat 。启动成功,看到starting....最后是started!

[2018-08-18T22:18:41,578][INFO ][o.e.n.Node               ] [-Jy0w6-] starting ...
[2018-08-18T22:18:44,044][INFO ][o.e.t.TransportService ] [-Jy0w6-] publish_address {127.0.0.1:9300}, bound_addresses {127.0.0.1:9300}, {[::1]:9300}
{ml.machine_memory=8441524224, xpack.installed=true, ml.max_open_jobs=20, ml.enabled=true}, reason: apply cluster state (from master [master {-Jy0w6-}{-Jy0w6-QTKquaudbtTAQMQ}
[2018-08-18T22:18:48,923][INFO ][o.e.x.s.t.n.SecurityNetty4HttpServerTransport] [-Jy0w6-] publish_address {127.0.0.1:9200}, bound_addresses {127.0.0.1:9200}, {[::1]:9200}
[2018-08-18T22:18:48,924][INFO ][o.e.n.Node ] [-Jy0w6-] started

​ 然后访问 http://localhost:9200/ ,页面响应json格式数据,服务启动正常!

2.2.2 实用插件Head安装(Windows)

ES 默认返回的信息在页面上是Json格式显示!不太友好!

Head插件的优点

  • 提供了友好的web界面,解决数据在界面显示问题
  • 实现基本信息的查看和Restful 请求的模拟以及数据的基本检索

1、安装Head的步骤

ElasticSearch-5.0安装head插件

ES6.0版本安装head插件

​ 1)、安装Node 6.x以上J环境,安装 执行指令npm install -g grunt -cli进行安装grunt。

​ 2)、 下载elasticsearch-head包,在Github【elasticsearch-head】上面,直接选择下载的DownLoad zip到本地!

​ 3)、保存在 F:\elasticsearch_learn\ 文件夹下面并对 elasticsearch-head 进行解压!

​ 4)、在 F:\elasticsearch_learn\elasticsearch-head-master文件夹目录下面,使用 npm install !

F:\elasticsearch_learn\elasticsearch-head-master>npm install

注意:第一次执行失败了!报了下面的错误(可能是网络不好的原因,网络好的时候在尝试执行一次),但是服务启动没有问题!

npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@^1.0.0
npm ERR! node v6.10.3
npm ERR! npm v3.10.10
npm ERR! code ELIFECYCLE
npm ERR! phantomjs-prebuilt@2.1.16 install: `node install.js`
npm ERR! Exit status 1
....
npm ERR! Please include the following file with any support request:
npm ERR! F:\elasticsearch_learn\elasticsearch-head-master\npm-debug.log

​ 5)、doc窗口 在 F:\elasticsearch_learn\elasticsearch-head-master文件夹目录下面执行

 # npm run start  或者  grunt server
F:\elasticsearch_learn\elasticsearch-head-master>npm run start

​ 6)、验证服务,默认访问地址http://localhost:9100,如下图显示:

2、修改相应的配置

ElasticSearch和 elasticsearch-head 本质上是两个服务进程,访问存在跨域问题,需要进行一些设置。

在 elasticsearch安装目录 /config/elasticsearch.yml ,在这个配置文件的末尾追加下面两行配置信息并保存!

http.cors.enabled: true
http.cors.allow-origin: "*"
属性 缺省值 描述
http.cors.enabled true 如果启用了 HTTP 端口,那么此属性会指定是否允许跨源 REST 请求。
http.cors.allowed.origin localhost 如果 http.cors.enabled 的值为 true,那么该属性会指定允许 REST 请求来自何处。

更多属性配置,请查看 【Elasticsearch 服务配置属性

3、验证elasticsearch和 elasticsearch-head

  • 启动 elasticsearch服务
  • 启动elasticsearch-head 服务

访问 http://localhost:9100 地址!查看elasticsearch 集群健康值是否正常!正常如下图:

注: 集群健康值

red(差):集群 健康状况很差,虽然可以查询,但是已经出现了丢失数据的现象 ;

yellow(中):集群健康状况不是很好,但是集群可以正常使用 ;

green(优):集群健康状况良好,集群正常使用。

2.3、ES安装-分布式安装

1)、安装说明,安装三个节点,一个master ,两个slave。

集群名称 ip-端口
myEsCluster (master) 127.0.0.1:9500
myEsCluster(slave) 127.0.0.1:9600
myEsCluster(slave) 127.0.0.1:9700

2)、Es安装包解压出三份ES,修改每个 elasticsearch安装目录 /config/elasticsearch.yml 这个配置文件

master配置说明:

# 设置支持elasticsearch-head
http.cors.enabled: true
http.cors.allow-origin: "*" # 设置集群master配置信息
# 首先要指定 集群的名字 ,名字随便起,符合常规命名规则
cluster.name: myEsCluster
# 节点的名字,一般为master 或者 slave
node.name: master
# 节点是否为master,设置为true的话,说明此节点为master节点
node.master: true
# 设置网络,如果是本机的话就是127.0.0.1,其他服务器配置对应的IP地址即可
network.host: 127.0.0.1
# 默认端口为 9200,可以修改默认设置
http.port: 9500

slave配置说明:

# 设置集群slave配置信息
# 首先要指定 集群的名字 ,名字随便起,符合常规命名规则
cluster.name: myEsCluster
# 节点的名字,一般为master 或者 slave
node.name: slave1
# 节点是否为master,设置为true的话,说明此节点为master节点
node.master: false
# 默认端口为 9200,可以修改默认设置
http.port: 9600
# 设置网络,如果是本机的话就是127.0.0.1,其他服务器配置对应的IP地址即可
network.host: 127.0.0.1
# 设置集群中master节点的初始列表,可以通过这些节点来自动发现新加入集群的节点。可以是一个数组。
# #discovery.zen.ping.unicast.hosts: ["host1", "host2"]
discovery.zen.ping.unicast.hosts: ["127.0.0.1"]

两个slave配置只需要改相应的端口号即可!一个slave1:9600 ,一个slave2:9700。

更多配置参考

3)、配置后完成后,启动master的,然后启动Slave,也启动elasticsearch-head服务,此时页面可以查看Es集群的状态!如下图所示:

2.4、 总结

从上面的安装来看,Es的安装相对还是比较简单,并且在安装分布式的时候,通过简单的配置就可以快速扩展多个ES节点,能够快速的进行扩容,非常灵活,方便!

三、ElasticSearch 基础概念

3.1、基本概念

集群和节点

集群:是由一个或者多个ES节点组成的集合。 每一个集群都有一个唯一的名字,默认是ElasticSearch。每个节点也都有唯一名字。

索引

索引: 含有相同属性的文档集合,比如产品的索引,用户的索引等

类型:索引可以定义一个或多个类型,文档必须属于一个类型(一般会定义有相同字段的文档为一个类型)

文档:文档是可以被所有的基本数据单位,是整个ES中最小的存储单位

索引在Es中是通过一个名字来识别的,而且它的名字必须是 英文字母小写,且不能有中划线

都是通过这个名字来进行增删查改。

ES 数据库
索引 实例database
类型 表-table
文档 一行记录

举例:图书索引 ---> 文学类型、技能类型...---->每一本书可以看成一个文档

分片和备份

分片: 每个索引都有多个分片,每个分片是一个Lucene索引

​ 分片的好处:假如数据量很大的话,就会造成硬盘的压力很大,同时搜索速度也会出现瓶颈,将索引分成多个分片,从而分摊压力提供效率。

备份:拷贝一份分片就完成了分片的备份,提供可用性

ES默认在创建索引的时候,会创建5个分片,1个备份。这个默认的数量是可以修改的。

​ number_of_shards: 每个索引的主分片数,默认值是 5 。这个配置在索引创建后不能修改。

​ number_of_replicas:每个主分片的副本数,默认值是 1 。对于活动的索引库,这个配置可以随时修改。

注意:索引的分片只能在创建索引的时候指定,而不能再后期进行修改。备份是可以动态修改的。

四、ElasticSearch 基本用法

ES是以Restful API的风格来命名的。

  • API 的基本格式

    http://:/<索引>/<类型>/<文档id>

  • 常用HTTP动词

    GET/PUT/POST/DELETE

4.1、索引的创建

问题:如何确定一个索引是非结构化还是结构的化的呢?

结合Head插件,索引-->索引信息,查看JSON数据中mappings,如果数据为空,则说明是非结构化索引。

非结构化创建

使用Head插件进行索引的创建,在tab标签上,选择索引,点 新建索引,输入索引的名称,注意名称的命名规则。(我自己验证,中文、有中划线的索引名字都可以创建成功!但是字母必须是小写!)

创建成功每个框框,都是Es索引的分片,粗线框是主分片 和 细线框 是分片的备份。

结构化创建

1)、使用Head插件进行索引的创建,在tab标签上,选择复合查询,进行如下配置:

2)、或者使用PostMan工具进行索引的创建

说明:

在Elasticsearch 6.0.0或更高版本中创建的索引只包含一个mapping type。 在5.x中使用multiple mapping types创建的索引将继续像以前一样在Elasticsearch 6.x中运行。 Mapping types将在Elasticsearch 7.0.0中完全删除。

Indices created in Elasticsearch 6.0.0 or later may only contain a single mapping type. Indices created in 5.x with multiple mapping types will continue to function as before in Elasticsearch 6.x. Mapping types will be completely removed in Elasticsearch 7.0.0.

PUT 127.0.0.1:9500/people

请求参数:

{
"settings":{
"number_of_shards":3,
"number_of_replicas":1
},
"mappings":{
"man":{
"properties":{
"name":{
"type":"text"
},
"age":{
"type":"integer"
},
"birth":{
"type":"date",
"format":"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
},
"country":{
"type":"keyword"
}
}
},
"woman":{} }
}

结果:

{
"acknowledged": true,
"shards_acknowledged": true,
"index": "people"
}

如果一个mappings中有两个type的话,在提交的时候会报如下错误:

PUT 127.0.0.1:9500/people2

参数:

{
"settings":{
"number_of_shards":3,
"number_of_replicas":1
},
"mappings":{
"man":{
"properties":{
"name":{
"type":"text"
},
"age":{
"type":"integer"
},
"birth":{
"type":"date",
"format":"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
},
"country":{
"type":"keyword"
}
}
},
"woman":{} }
}

结果:

{
"error": {
"root_cause": [
{
"type": "illegal_argument_exception",
"reason": "Rejecting mapping update to [people2] as the final mapping would have more than 1 type: [woman, man]"
}
],
"type": "illegal_argument_exception",
"reason": "Rejecting mapping update to [people2] as the final mapping would have more than 1 type: [woman, man]"
},
"status": 400
}

4.2、插入

文档ID是一个唯一索引值,指向我们的文档数据。

指定文档ID插入

PUT 127.0.0.1:9500/people/man/1

指定插入文档的ID为 1.

参数:

{
"name":"dufy",
"age":27,
"birth":"1992-09-28",
"country":"China"
}

请求结果:

{
"_index": "people",
"_type": "man",
"_id": "1", # id 为1
"_version": 1,
"result": "created", # 标识创建一个文档
"_shards": {
"total": 2,
"successful": 2,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1
}

使用Head插件查看数据:

自动产生文档ID插入

自动产生ID和上面指定ID插入不同的两个地方是:

(1)、在请求地址上不需要指定 ID,让ES自动帮我们创建ID!

(2)、请求方式为POST方式

POST 127.0.0.1:9500/people/man

请求参数:

{
"name":"dufy_auto_id",
"age":37,
"birth":"1982-09-28",
"country":"China"
}

请求结果:

{
"_index": "people",
"_type": "man",
"_id": "zmLSUGUBWifqa4luPRp5", # 自动创建ID
"_version": 1,
"result": "created", # 标识创建一个文档
"_shards": {
"total": 2,
"successful": 2,
"failed": 0
},
"_seq_no": 1,
"_primary_term": 1
}

使用Head插件查看数据:

4.3 、修改

直接修改文档

POST 127.0.0.1:9500/people/man/1/_update

注意:需要在请求的地址后面加上 _update,标识是一个修改操作。

请求参数:

{
"doc":{
"name":"dufy_update"
}
}

请求响应结果:

{
"_index": "people",
"_type": "man",
"_id": "1", # 标识文档的ID为1
"_version": 2,
"result": "updated", # 标识修改一个文档
"_shards": {
"total": 2,
"successful": 2,
"failed": 0
},
"_seq_no": 2,
"_primary_term": 1
}

通过Head插件查看,发现文档ID为1 name已经修改了。

脚本修改文档

脚本修改和直接修改的API是一样的,只是参数有些区别。

POST 127.0.0.1:9500/people/man/1/_update

第一种方式请求参数:

{
"script":{
"lang":"painless" , # ES 脚本语言
"inline":"ctx._source.age += 10" #ctx:es上下文,_source:代表es当前的文档,age:字段
}
}

第二种方式请求参数:

{
"script":{
"lang":"painless" ,
"inline":"ctx._source.age = params.age",
"params":{ #使用params 指定数据值
"age":80
}
}
}

4.4、删除

删除文档

DELETE 127.0.0.1:9500/people/man/1

使用delete请求,通过文档的ID进行删除操作。

{
"_index": "people",
"_type": "man",
"_id": "1",
"_version": 5,
"result": "deleted", # 标识删除一个文档
"_shards": {
"total": 2,
"successful": 2,
"failed": 0
},
"_seq_no": 5,
"_primary_term": 1
}

删除索引

删除操作是一个比较危险的操作,因为索引一旦删除,对应的所有数据全部被删除了。

  • 可以通过Head插件删除。确认输入删除,索引就删除了。

  • 使用 PostMan进行删除,使用 请求,只输入请求的索引

    127.0.0.1:9500/people

4.5、查询-重点

查询功能是使用过操作比较频繁的。

首先进行数据初始化,创建一个book 的索引,然后插入一些数据。具体的创建索引和插入数据,查看之前内容。

PUT 127.0.0.1:9500/book

结构化创建:

{
"mappings":{
"novel":{
"properties":{
"author":{
"type":"text"
},
"word_count":{
"type":"integer"
},
"publish_date":{
"type":"date",
"format":"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
},
"title":{
"type":"keyword"
}
}
}
}
}

插入文档数据:

POST 127.0.0.1:9500/book/novel/1

{
"title":"Nginx",
"word_count":5000,
"publish_date":"2992-09-28",
"author":"zhangyc"
}

简单查询

GET 127.0.0.1:9500/book/novel/4

{
"_index": "book",
"_type": "novel",
"_id": "4",
"_version": 1,
"found": true,
"_source": { # 查询出来索引为book,类型是novel的ID=4 的文档数据
"title": "Dubbo",
"word_count": 8000,
"publish_date": "1992-09-28",
"author": "alibb"
}
}

条件查询

POST 127.0.0.1:9500/book/_search

  • 查询全部数据
{
"query":{ # 查询是以query为关键词的
"match_all":{} # 查询全部的数据
}
}

返回结果:

{
"took": 8, # 接口响应花费的时间/ms
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 5, # 总共数据5条
"max_score": 1,
"hits": [ # 击中,也就是响应的全部数据,hits默认返回的数据为10条,可以修改!
{
"_index": "book",
"_type": "novel",
"_id": "5",
"_score": 1,
"_source": {
"title": "Nginx",
"word_count": 5000,
"publish_date": "2992-09-28",
"author": "zhangyc"
}
},
{....} #其他的数据信息
}
]
}
}

修改 hits默认返回数据的总数。

{
"query":{ # 查询是以query为关键词的
"match_all":{} # 查询全部的数据
},
"size":2 # 返回数据的总数
}
  • 关键词查询

    POST 127.0.0.1:9500/book/_search

{
"query":{
"match":{
"title": "Redis实战"
},
# 默认 排序 使用 _score
"sort":[ # 如何查询数据较多,可以进行排序操作
{"publish_date":{"order":"desc"}}
]
}
}
{
"took": 7,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 0.2876821,
"hits": [
{
"_index": "book",
"_type": "novel",
"_id": "3",
"_score": 0.2876821,
"_source": {
"title": "Redis实战",
"word_count": 2000,
"publish_date": "1582-09-28",
"author": "marry"
}
}
]
}
}

聚合查询

POST 127.0.0.1:9500/book/_search

  • 对书籍的字数进行聚合

查询参数:

{
"aggs":{
"groud_word_count":{ # 自定义聚合名称
"terms":{
"field":"word_count"
}
}
}
}

返回结果:

{
# 其他数据省略
"aggregations": {
"groud_word_count": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": 5000,
"doc_count": 2 # 文档总数
},
{
"key": 2000,
"doc_count": 1
},
{
"key": 8000,
"doc_count": 1
},
{
"key": 10000,
"doc_count": 1
}
]
}
}
}

上面这个是单个聚合,多个聚合同理:

{
"aggs":{
"groud_word_count":{ # 自定义聚合名称
"terms":{
"field":"word_count"
}
},
"groud_title":{ # 自定义聚合名称
"terms":{
"field":"title"
}
}
}
}
  • 进行函数计算
{
"aggs":{
"grades_word_count":{
"stats":{ #统计数据 min 、max、avg、avg
"field":"word_count"
}
}
}
}

返回结果:

"aggregations": { # 聚合
"grades_word_count": {
"count": 5,
"min": 2000,
"max": 10000,
"avg": 6000,
"sum": 30000
}
}

五、ElasticSearch 高级查询

Elasticsearch Reference 6

子条件查询

特定字段查询 所指特定值

1、Query Context

在查询过程中,除了判断文档是否满足查询条件外,ES还会计算一个_score来标识匹配的程度,旨在判断目标文档和查询条件匹配的有多好(匹配度)!

  • 全文本查询 —— 针对文本类型数据
  • 字段级别查询——针对结构化数据,如数字、日期等
{
"query":{
"multi_match":{ # 多条件查询
"query":"Redis",
"fields":["title","author"]
}
} }

语法查询:

{
"query":{
"query_string":{
"query":"入门 OR Redis",
"fields":["title","author"]
}
} }

字段级别的查询:

{
"query":{
"term":{
"word_count":5000
}
} }

字数或者日期范围:

{
"query":{
"range":{
"word_count":{
"gte":1000,
"lte":5000
}
}
} }
2、Filter Context
{
"query":{
"bool":{
"filter":{
"term":{
"word_count":5000
}
}
}
} }

复合条件查询

以一定的逻辑组合子条件查询,结合了Query和Filter Context

  • 固定分数查询

  • 布尔查询

六、ElasticSearch 实战演练

1、配置Spring boot ElasticSearch开发环境

1、创建Spring boot web项目,spring boot 使用2.0.4版本, elasticsearch为5.6.10

 <parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent> <!--引入ELasticSearch的依赖包,默认使用elasticsearch5.6.10版本-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<!--需要引入transport-netty3-client,否则会启动报错-->
<dependency>
<groupId>org.elasticsearch.plugin</groupId>
<artifactId>transport-netty3-client</artifactId>
<version>5.6.10</version>
</dependency>

2、配置代码

/**
* ES 配置类
* @author:dufyun
* @version:1.0.0
* @date 2018/8/19
* @update:[日期YYYY-MM-DD] [更改人姓名][变更描述]
*/
@Configuration
public class ElasticSearchConfig { private static final Logger logger = LoggerFactory.getLogger(ElasticSearchConfig.class); @Bean
public TransportClient transportClient() {
logger.info("初始化开始。。。。。");
TransportClient client = null;
try {
TransportAddress transportAddress = new InetSocketTransportAddress(InetAddress.getByName("localhost"),
Integer.valueOf(9300)); // 配置信息
Settings esSetting = Settings.builder()
.put("cluster.name","myEsCluster")
.build(); //配置信息Settings自定义,下面设置为EMPTY
client = new PreBuiltTransportClient(esSetting); client.addTransportAddresses(transportAddress); } catch (Exception e) {
logger.error("elasticsearch TransportClient create error!!!", e);
} return client;
}
}

也可以使用配置文件!

es.hostName=localhost
es.transport=9300
es.cluster.name=myEsCluster
@Configuration
@PropertySource(value={"classpath:elasticsearch.properties"}) // 加载 指定的配置,只支持properti
public class ElasticSearchConfig { private static final Logger logger = LoggerFactory.getLogger(ElasticSearchConfig.class); @Value("${es.hostName}")
private String hostName; @Value("${es.transport}")
private Integer transport; @Value("${es.cluster.name}")
private String clusterName; @Bean
public TransportClient transportClient() {
LOGGER.info("初始化开始。。。。。");
TransportClient client = null;
try {
TransportAddress transportAddress = new InetSocketTransportAddress(InetAddress.getByName(hostName),
Integer.valueOf(transport)); // 配置信息
Settings esSetting = Settings.builder()
.put("cluster.name",clusterName)
.build(); //配置信息Settings自定义,下面设置为EMPTY
client = new PreBuiltTransportClient(esSetting); client.addTransportAddresses(transportAddress); } catch (Exception e) {
logger.error("elasticsearch TransportClient create error!!!", e);
} return client;
}
}

3、使用单元测试进行验证

@Autowired
private TransportClient client; @Test
public void contextLoads() { System.out.println(client);
//org.elasticsearch.transport.client.PreBuiltTransportClient@6c9b44bf
}

2、接口开发

1、新增图书信息功能开发

2、修改图书信息功能开发

3、删除功能开发

4、综合查询接口开发

代码如下:

/**
* ES book索引 控制器
* @author:dufyun
* @version:1.0.0
* @date 2018/8/19
* @update:[日期YYYY-MM-DD] [更改人姓名][变更描述]
*/
@Controller
public class BookController { @Autowired
private TransportClient client; /**
* http://localhost:8080/get/book/novel?id=2
* 获取Es中数据
* @param id
* @return
*/
@GetMapping(value = "/get/book/novel")
@ResponseBody
public ResponseEntity getBook(@RequestParam("id") String id) {
if (StringUtils.isEmpty(id)) {
return new ResponseEntity("ID不能为空!", HttpStatus.NOT_FOUND);
}
GetResponse result = client.prepareGet("book", "novel", id).get(); if (!result.isExists()) {
return new ResponseEntity("资源没有找到!", HttpStatus.NOT_FOUND);
} return new ResponseEntity(result.getSource(), HttpStatus.OK); } /**
* 添加文档数据
* http://localhost:8080/add/book/novel
* form-data
* @param title
* @param author
* @param word_count
* @param publish_date
* @return
*/
@PostMapping(value = "/add/book/novel")
@ResponseBody
public ResponseEntity addBook(@RequestParam("title") String title, @RequestParam("author") String author,
@RequestParam("word_count") Integer word_count,
@RequestParam("publish_date") String publish_date) { try {
/**
* 要加 startObject,否则出现 Can not write a field name, expecting a value 错误!
*/
XContentBuilder builder = XContentFactory.jsonBuilder().startObject().field("title", title)
.field("author", author).field("word_count", word_count)
.field("publish_date", publish_date).endObject(); IndexResponse indexResponse = client.prepareIndex("book", "novel").setSource(builder).get(); return new ResponseEntity(indexResponse.getId(), HttpStatus.INTERNAL_SERVER_ERROR);
} catch (IOException e) {
e.printStackTrace();
new ResponseEntity("内部服务错误!", HttpStatus.INTERNAL_SERVER_ERROR);
}
return new ResponseEntity("插入出错!", HttpStatus.INTERNAL_SERVER_ERROR); } /**
* 删除Es中数据
* localhost:8080/del/book/novel?id=sdfhUWUB1-6vN1-K8u5f
* @param id
* @return
*/
@DeleteMapping(value = "/del/book/novel")
@ResponseBody
public ResponseEntity delBook(@RequestParam("id") String id) {
if (StringUtils.isEmpty(id)) {
return new ResponseEntity("ID不能为空!", HttpStatus.NOT_FOUND);
}
DeleteResponse result = client.prepareDelete("book", "novel", id).get(); return new ResponseEntity(result.toString(), HttpStatus.OK); } /**
* 更新文档
*
* @param id
* @param title
* @param author
* @param word_count
* @param publish_date
* @return
*/
@PutMapping(value = "/update/book/novel")
@ResponseBody
public ResponseEntity updateBook(@RequestParam("id") String id,
@RequestParam(value = "title",required = false) String title,
@RequestParam(value = "author",required = false) String author,
@RequestParam(value = "word_count",required = false) Integer word_count,
@RequestParam(value = "publish_date",required = false) String publish_date) {
if (StringUtils.isEmpty(id)) {
return new ResponseEntity("ID不能为空!", HttpStatus.NOT_FOUND);
}
UpdateRequest updateRequest = new UpdateRequest("book","novel",id); try {
XContentBuilder builder = XContentFactory.jsonBuilder().startObject();
if (!StringUtils.isEmpty(title)){
builder.field("title", title);
}
if (!StringUtils.isEmpty(author)){
builder.field("author", author);
}
if (!StringUtils.isEmpty(word_count)){
builder.field("word_count", word_count);
}
if (!StringUtils.isEmpty(publish_date)){
builder.field("publish_date", publish_date);
} builder.endObject(); updateRequest.doc(builder); UpdateResponse updateResponse = client.update(updateRequest).get(); return new ResponseEntity(updateResponse.getId(), HttpStatus.OK);
} catch (Exception e) {
e.printStackTrace();
return new ResponseEntity("内部错误!", HttpStatus.INTERNAL_SERVER_ERROR);
} } /**
* localhost:8080/query/book/novel
* 复合查询接口
* @param title
* @param author
* @param gt_word_conut
* @param lt_word_conut
* @return
*/
@PostMapping(value = "/query/book/novel")
@ResponseBody
public ResponseEntity queryBook(
@RequestParam(value = "title",required = false) String title,
@RequestParam(value = "author",required = false) String author,
@RequestParam(value = "gt_word_conut",defaultValue = "0") int gt_word_conut,
@RequestParam(value = "lt_word_conut",required = false) Integer lt_word_conut) { BoolQueryBuilder boolQuy = QueryBuilders.boolQuery(); if(!StringUtils.isEmpty(title)){
boolQuy.must(QueryBuilders.matchQuery("title", title));
}
if(!StringUtils.isEmpty(author)){
boolQuy.must(QueryBuilders.matchQuery("author", author));
} RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("word_count").from(gt_word_conut); if(lt_word_conut != null && gt_word_conut >0){
rangeQueryBuilder.to(lt_word_conut);
}
boolQuy.filter(rangeQueryBuilder); SearchRequestBuilder searchRequestBuilder = client.prepareSearch("book")
.setTypes("novel")
.setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
.setQuery(boolQuy)
.setFrom(0)
.setSize(10);
SearchResponse searchResponse = searchRequestBuilder.get();
List<Map<String, Object>> lists = new ArrayList<>();
for (SearchHit hit:searchResponse.getHits().getHits()) {
lists.add(hit.getSource());
} return new ResponseEntity(lists,HttpStatus.OK);
} }

七、ElasticSearch 总结

  • ES简介——使用场景(重要性),提高竞争力
  • 安装ES-单机-分布式
  • 核心基础概念
  • 基本使用方法 ——增删查改
  • 高级查询语法——重点和难点
  • 实战演练

实战演练源码

springboot-elasticsearch


如果您觉得这篇博文对你有帮助,请点赞或者喜欢,让更多的人看到,谢谢!

如果帅气(美丽)、睿智(聪颖),和我一样简单善良的你看到本篇博文中存在问题,请指出,我虚心接受你让我成长的批评,谢谢阅读!
祝你今天开心愉快!


欢迎访问我的csdn博客,我们一同成长!

不管做什么,只要坚持下去就会看到不一样!在路上,不卑不亢!

博客首页 : http://blog.csdn.net/u010648555

© 每天都在变得更好的阿飞

ElasticSearch 入门总结的更多相关文章

  1. ElasticSearch入门-搜索如此简单

    搜索引擎我也不是很熟悉,但是数据库还是比较了解.可以把搜索理解为数据库的like功能的替代品.因为like有以下几点不足: 第一.like的效率不行,在使用like时,一般都用不到索引,除非使用前缀匹 ...

  2. ElasticSearch入门知识扫盲

    ElasticSearch 入门介绍 tags: 第三方 lucene [toc] 1. what Elastic Search(ES)是什么 全文检索和lucene 全文检索 优点:高效,准确,分词 ...

  3. 《读书报告 -- Elasticsearch入门 》--简单使用(2)

    <读书报告 – Elasticsearch入门 > ' 第四章 分布式文件存储 这章的主要内容是理解数据如何在分布式系统中存储. 4.1 路由文档到分片 创建一个新文档时,它是如何确定应该 ...

  4. 《读书报告 -- Elasticsearch入门 》-- 安装以及简单使用(1)

    <读书报告 – Elasticsearch入门 > 第一章 Elasticsearch入门 Elasticsearch是一个实时的分布式搜索和分析引擎,使得人们可以在一定规模上和一定速度上 ...

  5. ElasticSearch入门 附.Net Core例子

    1.什么是ElasticSearch? Elasticsearch是基于Lucene的搜索引擎.它提供了一个分布式,支持多租户的全文搜索引擎,它具有HTTP Web界面和无模式JSON文档. Elas ...

  6. ElasticSearch入门点滴

    这是Elasticsearch-6.2.4 版本系列的第一篇: ElasticSearch入门 第一篇:Windows下安装ElasticSearch ElasticSearch入门 第二篇:集群配置 ...

  7. 全文搜索引擎Elasticsearch入门实践

    全文搜索引擎Elasticsearch入门实践 感谢阮一峰的网络日志全文搜索引擎 Elasticsearch 入门教程 安装 首先需要依赖Java环境.Elasticsearch官网https://w ...

  8. Elasticsearch Elasticsearch入门指导

    Elasticsearch入门指导 By:授客 QQ:1033553122 1. 开启elasticsearch服务器 1 2. 基本概念 2 <1> 集群(Cluster) 2 < ...

  9. ElasticSearch 入门

    http://www.oschina.net/translate/elasticsearch-getting-started?cmp ElasticSearch 简单入门 返回原文英文原文:Getti ...

  10. 全文搜索引擎 Elasticsearch 入门

    1. 百科 ElasticSearch是一个基于Lucene的搜索服务器.它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口.Elasticsearch是用Java开发的,并作 ...

随机推荐

  1. CF #442 div2

    A 判断下5个名字出现了几次.pre数据巨弱,就这么一水题在std测刷掉了非常多的人.. /** @Date : 2017-10-24 16:04:41 * @FileName: A.cpp * @P ...

  2. linux下编译make文件报错“/bin/bash^M: 坏的解释器,使用grep快速定位代码位置

    一.linux下编译make文件报错“/bin/bash^M: 坏的解释器 参考文章:http://blog.csdn.net/liuqiyao_01/article/details/41542101 ...

  3. Tju_Oj_3988Password

    这个题是给树的前序和中序,输出后序. 做法是根据前序找根,根据根在中序中找中序的左右子树,根据左右子树长度找前序的左右子树,依此递归. 做过之后感觉还是比较基础的,废话不多说,上题上代码. Bob w ...

  4. 【配置】Spring和MyBatis整合

    spring配置文件: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="h ...

  5. 转载 你不知道的super

    http://funhacks.net/2016/11/09/super/ super仅被用于新式类 在类的继承中,如果重定义某个方法,该方法会覆盖父类的同名方法,但有时,我们希望能同时实现父类的功能 ...

  6. 工作目录与os.getcwd()

    假设某程序在/root/a/aa.py,在shell,当前pwd为/root,输入./a/aa.py运行py程序,则爱程序的工作目录是/root.而不是程序所在文件夹,os.getcwd()就是查看工 ...

  7. AC自动机(Keywords Search)

    题目链接:https://cn.vjudge.net/contest/280743#problem/A 题目大意:首先给你T组测试样例,然后给你n个字符串,最后再给你一个模式串,然后问你这一些字符串中 ...

  8. (FFT) A * B Problem Plus

    题目链接:https://cn.vjudge.net/contest/280041#problem/F 题目大意:给你两个数,求这俩数相乘的结果.(长度最长5000) 具体思路:硬算肯定是不行的,比如 ...

  9. arm GIC介绍之一【转】

    转自:https://blog.csdn.net/sunsissy/article/details/73791470 GIC是ARM架构中及其重要的部分,本文只在公开ARM对应资料基础上,以MTK开发 ...

  10. 理解 Memory barrier(内存屏障)【转】

    转自:http://name5566.com/4535.html 参考文献列表:http://en.wikipedia.org/wiki/Memory_barrierhttp://en.wikiped ...