Elasticsearch(一)Docker搭建ES集群

关闭防火墙

后面我们要使用多个端口,为了避免繁琐的开放端口操作,我们关掉防火墙

# 关闭防火墙
systemctl stop firewalld.service# 禁用防火墙
systemctl disable firewalld.service

安装Docker

我们使用 Docker 来运行 Elasticsearch,首先安装 Docker

下载 Elastic Search 镜像

docker pull elasticsearch:7.9.3

集群部署结构

在一台服务器上,使用Docker部署三个ES容器组成的集群

准备虚拟网络和挂载目录

# 创建虚拟网络
docker network create es-net# node1 的挂载目录
mkdir -p -m 777 /var/lib/es/node1/plugins
mkdir -p -m 777 /var/lib/es/node1/data# node2 的挂载目录
mkdir -p -m 777 /var/lib/es/node2/plugins
mkdir -p -m 777 /var/lib/es/node2/data# node3 的挂载目录
mkdir -p -m 777 /var/lib/es/node3/plugins
mkdir -p -m 777 /var/lib/es/node3/data

设置 max_map_count

必须修改系统参数 max_map_count,否则 Elasticsearch 无法启动:

在 /etc/sysctl.conf 文件中添加 vm.max_map_count=262144

echo 'vm.max_map_count=262144' >>/etc/sysctl.conf

需要重启服务器!

确认参数配置:

cat /etc/sysctl.conf

启动 Elasticsearch 集群

node1:

docker run -d \--name=node1 \--restart=always \--net es-net \-p 9200:9200 \-p 9300:9300 \-v /var/lib/es/node1/plugins:/usr/share/elasticsearch/plugins \-v /var/lib/es/node1/data:/usr/share/elasticsearch/data \-e node.name=node1 \-e node.master=true \-e network.host=node1 \-e discovery.seed_hosts=node1,node2,node3 \-e cluster.initial_master_nodes=node1 \-e cluster.name=es-cluster \-e "ES_JAVA_OPTS=-Xms256m -Xmx256m" \elasticsearch:7.9.3

环境变量说明:

环境变量    说明
node.name    节点在集群中的唯一名称
node.master    可已被选举为主节点
network.host    当前节点的地址
discovery.seed_hosts    集群中其他节点的地址列表
cluster.initial_master_nodes    候选的主节点地址列表
cluster.name    集群名
ES_JAVA_OPTS    java虚拟机参数
参考 Networking | Elasticsearch Guide [8.1] | Elastic

node2:

docker run -d \--name=node2 \--restart=always \--net es-net \-p 9201:9200 \-p 9301:9300 \-v /var/lib/es/node2/plugins:/usr/share/elasticsearch/plugins \-v /var/lib/es/node2/data:/usr/share/elasticsearch/data \-e node.name=node2 \-e node.master=true \-e network.host=node2 \-e discovery.seed_hosts=node1,node2,node3 \-e cluster.initial_master_nodes=node1 \-e cluster.name=es-cluster \-e "ES_JAVA_OPTS=-Xms256m -Xmx256m" \elasticsearch:7.9.3

node3:

docker run -d \--name=node3 \--restart=always \--net es-net \-p 9202:9200 \-p 9302:9300 \-v /var/lib/es/node3/plugins:/usr/share/elasticsearch/plugins \-v /var/lib/es/node3/data:/usr/share/elasticsearch/data \-e node.name=node3 \-e node.master=true \-e network.host=node3 \-e discovery.seed_hosts=node1,node2,node3 \-e cluster.initial_master_nodes=node1 \-e cluster.name=es-cluster \-e "ES_JAVA_OPTS=-Xms256m -Xmx256m" \elasticsearch:7.9.3

查看启动结果结果

http://192.168.64.181:9200

http://192.168.64.181:9200/_cat/nodes

chrome浏览器插件:elasticsearch-head

elasticsearch-head 项目提供了一个直观的界面,可以很方便地查看集群、分片、数据等等。elasticsearch-head最简单的安装方式是作为 chrome 浏览器插件进行安装。

在 elasticsearch-head 项目仓库中下载 chrome 浏览器插件
https://github.com/mobz/elasticsearch-head/raw/master/crx/es-head.crx

将文件后缀改为 zip

解压缩

在 chrome 浏览器中选择“更多工具”–“扩展程序”

在“扩展程序”中确认开启了“开发者模式”

点击“加载已解压的扩展程序”

选择前面解压的插件目录

在浏览器中点击 elasticsearch-head 插件打开 head 界面,并连接 http://192.168.64.181:9200/

Elasticsearch(二)IK中文分词器

安装 ik 分词器

从 ik 分词器项目仓库中下载 ik 分词器安装包,下载的版本需要与 Elasticsearch 版本匹配
GitHub - medcl/elasticsearch-analysis-ik: The IK Analysis plugin integrates Lucene IK analyzer into elasticsearch, support customized dictionary.

或者可以访问 gitee 镜像仓库:
Gitee 极速下载/elasticsearch-analysis-ik

下载 elasticsearch-analysis-ik-7.9.3.zip 复制到 /root/ 目录下

在三个节点上安装 ik 分词器

cd ~/# 复制 ik 分词器到三个 es 容器
docker cp elasticsearch-analysis-ik-7.9.3.zip node1:/root/
docker cp elasticsearch-analysis-ik-7.9.3.zip node2:/root/
docker cp elasticsearch-analysis-ik-7.9.3.zip node3:/root/# 在 node1 中安装 ik 分词器
docker exec -it node1 elasticsearch-plugin install file:///root/elasticsearch-analysis-ik-7.9.3.zip# 在 node2 中安装 ik 分词器
docker exec -it node2 elasticsearch-plugin install file:///root/elasticsearch-analysis-ik-7.9.3.zip# 在 node3 中安装 ik 分词器
docker exec -it node3 elasticsearch-plugin install file:///root/elasticsearch-analysis-ik-7.9.3.zip# 重启三个 es 容器
docker restart node1 node2 node3

查看安装结果

在浏览器中访问 http://192.168.64.181:9200/_cat/plugins

如果插件不可用,可以卸载后重新安装:

docker exec -it node1 elasticsearch-plugin remove analysis-ikdocker exec -it node2 elasticsearch-plugin remove analysis-ikdocker exec -it node3 elasticsearch-plugin remove analysis-ik

ik分词测试

ik分词器提供两种分词器: ik_max_word 和 ik_smart

ik_max_word: 会将文本做最细粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,中华人民,中华,华人,人民共和国,人民,人,民,共和国,共和,和,国国,国歌”,会穷尽各种可能的组合,适合 Term Query;

ik_smart: 会做最粗粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,国歌”,适合 Phrase 查询。

ik_max_word 分词测试

使用 head 执行下面测试:
向 http://192.168.64.181:9200/_analyze 路径提交 POST 请求,并在协议体中提交 Json 数据:

{"analyzer":"ik_max_word","text":"中华人民共和国国歌"
}

ik_smart 分词测试

使用 head 执行下面测试:
向 http://192.168.64.181:9200/_analyze 路径提交 POST 请求,并在协议体中提交 Json 数据:

{"analyzer":"ik_smart","text":"中华人民共和国国歌"
}

Elasticsearch(三)使用 Kibana 操作 ES

下载 Kibana 镜像

docker pull kibana:7.9.3

启动 Kibana 容器

docker run \
-d \
--name kibana \
--net es-net \
-p 5601:5601 \
-e ELASTICSEARCH_HOSTS='["http://node1:9200","http://node2:9200","http://node3:9200"]' \
--restart=always \
kibana:7.9.3

启动后,浏览器访问 Kibana,进入 Dev Tools
http://192.168.64.181:5601/

索引、分片和副本

索引

Elasticsearch索引用来存储我们要搜索的数据,以倒排索引结构进行存储。

例如,要搜索商品数据,可以创建一个商品数据的索引,其中存储着所有商品的数据,供我们进行搜索:

当索引中存储了大量数据时,大量的磁盘io操作会降低整体搜索新能,这时需要对数据进行分片存储。

索引分片

在一个索引中存储大量数据会造成性能下降,这时可以对数据进行分片存储。

每个节点上都创建一个索引分片,把数据分散存放到多个节点的索引分片上,减少每个分片的数据量来提高io性能:

每个分片都是一个独立的索引,数据分散存放在多个分片中,也就是说,每个分片中存储的都是不同的数据。搜索时会同时搜索多个分片,并将搜索结果进行汇总。

如果一个节点宕机分片不可用,则会造成部分数据无法搜索

为了解决这一问题,可以对分片创建多个副本来解决。

索引副本

对分片创建多个副本,那么即使一个节点宕机,其他节点中的副本分片还可以继续工作,不会造成数据不可用:

分片的工作机制:

  1. 主分片的数据会复制到副本分片
  2. 搜索时,以负载均衡的方式工作,提高处理能力
  3. 主分片宕机时,其中一个副本分片会自动提升为主分片

下面我们就以上图的结构来创建 products 索引

创建索引

创建一个名为 products 的索引,用来存储商品数据。

分片和副本参数说明:

我们有三个节点,在每个节点上都创建一个分片。每个分片在另两个节点上各创建一个副本。

# 创建索引,命名为 products
PUT /products
{"settings": {"number_of_shards": 3, "number_of_replicas": 2}
}

用索引名称过滤,查看 products 索引:

粗框为主分片,细框为副本分片

映射(数据结构)

类似于数据库表结构,索引数据也被分为多个数据字段,并且需要设置数据类型和其他属性。

映射,是对索引中字段结构的定义和描述。

字段的数据类型

常用类型:

  • 数字类型:

    • byte、short、integer、long
    • float、double
    • unsigned_long
  • 字符串类型:

    • text : 会进行分词
    • keyword : 不会进行分词,适用于email、主机地址、邮编等
  • 日期和时间类型:

    • date

类型参考:

Field data types | Elasticsearch Guide [8.1] | Elastic

创建映射

在 products 索引中创建映射。

分词器设置:

  • analyzer:在索引中添加文档时,text类型通过指定的分词器分词后,再插入倒排索引
  • search_analyzer:使用关键词检索时,使用指定的分词器对关键词进行分词

查询时,关键词优先使用 search_analyzer 设置的分词器,如果 search_analyzer 不存在则使用 analyzer 分词器。

# 定义mapping,数据结构
PUT /products/_mapping
{"properties": {"id": {"type": "long"},"title": {"type": "text","analyzer": "ik_max_word","search_analyzer": "ik_smart"},"category": {"type": "text","analyzer": "ik_smart","search_analyzer": "ik_smart"},"price": {"type": "float"},"city": {"type": "text","analyzer": "ik_smart","search_analyzer": "ik_smart"},"barcode": {"type": "keyword"}}
}

映射参考:

Mapping | Elasticsearch Guide [8.1] | Elastic

查看映射

GET /products/_mapping

添加文档

添加的文档会有一个名为_id的文档id,这个文档id可以自动生成,也可以手动指定,通常可以使用数据的id作为文档id。

# 添加文档
PUT /products/_doc/10033
{"id":"10033","title":"SONOS PLAY:5(gen2) 新一代PLAY:5无线智能音响系统 WiFi音箱家庭,潮酷数码会场","category":"潮酷数码会场","price":"3980.01","city":"上海","barcode":"527848718459"
}PUT /products/_doc/10034
{"id":"10034","title":"天猫魔盒 M13网络电视机顶盒 高清电视盒子wifi 64位硬盘播放器","category":"潮酷数码会场","price":"398.00","city":"浙江杭州","barcode":"522994634119"
}PUT /products/_doc/10035
{"id":"10035","title":"BOSE SoundSport耳塞式运动耳机 重低音入耳式防脱降噪音乐耳机","category":"潮酷数码会场","price":"860.00","city":"浙江杭州","barcode":"526558749068"
}PUT /products/_doc/10036
{"id":"10036","title":"【送支架】Beats studio Wireless 2.0无线蓝牙录音师头戴式耳机","category":"潮酷数码会场","price":"2889.00","city":"上海","barcode":"37147009748"
}PUT /products/_doc/10037
{"id":"10037","title":"SONOS PLAY:1无线智能音响系统 美国原创WiFi连接 家庭桌面音箱","category":"潮酷数码会场","price":"1580.01","city":"上海","barcode":"527783392239"
}

也可以自动生成 _id 值:

POST /products/_doc
{"id":"10027","title":"vivo X9前置双摄全网通4G美颜自拍超薄智能手机大屏vivox9","category":"手机会场","price":"2798.00","city":"广东东莞","barcode":"541396973568"
}

查看文档:

GET /products/_doc/10037

查看指定文档title字段的分词结果:

GET /products/_doc/10037/_termvectors?fields=title

修改文档

底层索引数据无法修改,修改数据实际上是先删除再重新添加。

两种修改方式:

  • PUT:对文档进行完整的替换
  • POST:可以修改一部分字段

修改价格字段的值:

# 修改文档 - 替换
PUT /products/_doc/10037
{"id":"10037","title":"SONOS PLAY:1无线智能音响系统 美国原创WiFi连接 家庭桌面音箱","category":"潮酷数码会场","price":"9999.99","city":"上海","barcode":"527783392239"
}

查看文档:

GET /products/_doc/10037

修改价格和城市字段的值:

# 修改文档 - 更新部分字段
POST /products/_update/10037
{"doc": {"price":"8888.88","city":"深圳"}
}

查看文档:

GET /products/_doc/10037

删除文档

DELETE /products/_doc/10037

清空

POST /products/_delete_by_query
{"query": {"match_all": {}}
}

删除索引

# 删除 products 索引
DELETE /products

可以尝试用不同的分片和副本值来重新创建 products 索引

Elasticsearch(四)搜索

导入测试数据

为了测试搜索功能,我们首先导入测试数据,3160条商品数据,数据样例如下:

{ "index": {"_index": "pditems", "_id": "536563"}}
{ "id":"536563","brand":"联想","title":"联想(Lenovo)小新Air13 Pro 13.3英寸14.8mm超轻薄笔记本电脑","sell_point":"清仓!仅北京,武汉仓有货!","price":"6688.0","barcode":"","image":"/images/server/images/portal/air13/little4.jpg","cid":"163","status":"1","created":"2015-03-08 21:33:18","updated":"2015-04-11 20:38:38"}

下载测试数据

Elasticsearch测试数据,3160条商品数据_elasticsearch测试数据-Java文档类资源-CSDN下载

将压缩文件中的 pditems.json 上传到服务器

创建索引和映射

PUT /pditems
{"settings": {"number_of_shards": 3, "number_of_replicas": 2},"mappings": {"properties": {"id": {"type": "long"},"brand": {"type": "text","analyzer": "ik_smart"},"title": {"type": "text","analyzer": "ik_max_word"},"sell_point": {"type": "text","analyzer": "ik_max_word","search_analyzer": "ik_smart"},"price": {"type": "float"},"image": {"type": "keyword"},"cid": {"type": "long"},"status": {"type": "byte"},"created": {"type": "date","format": "yyyy-MM-dd HH:mm:ss"},"updated": {"type": "date","format": "yyyy-MM-dd HH:mm:ss"}} }
}

用 head 查看索引:

导入数据

在服务器上,进入 pditems.json 所在的文件夹,执行批量数据导入:

curl -XPOST 'localhost:9200/pditems/_bulk' \-H 'Content-Type:application/json' \--data-binary @pditems.json

查看数据

搜索 pditems 索引中全部 3160 条数据:

GET /pditems/_search
{"query": {"match_all": {}},"size": 3160
}

搜索文档

搜索所有数据

# 搜索 pditems 索引中全部数据
POST /pditems/_search
{"query": {"match_all": {}}
}

关键词搜索

# 查询 pditems 索引中title中包含"电脑"的商品
POST /pditems/_search
{"query": {"match": {"title": "电脑"}}
}

搜索结果过滤器

# 价格大于2000,并且title中包含"电脑"的商品
POST /pditems/_search
{"query": {"bool": {"must": [{"match": {"title": "电脑"}}],"filter": [{"range": {"price": {"gte": "2000"}}}]}}
}

搜索结果高亮显示

POST /pditems/_search
{"query": {"multi_match":{"query": "手机","fields": ["title", "sell_point"]}},"highlight" : {"pre_tags" : ["<i class=\"highlight\">"],"post_tags" : ["</i>"],"fields" : {"title" : {},"sell_point" : {"pre_tags": "<em>","post_tags": "</em>"}}}
}

Elasticsearch(五)Spring Data Elasticsearch - 增删改查API

Spring Data Elasticsearch

Spring Data Elasticsearch - Reference Documentation

Spring Data Elasticsearch 是 Elasticsearch 搜索引擎开发的解决方案。它提供:

模板对象,用于存储、搜索、排序文档和构建聚合的高级API。

例如,Repository 使开发者能够通过定义具有自定义方法名称的接口来表达查询。

案例说明

在 Elasticsearch 中存储学生数据,并对学生数据进行搜索测试。

数据结构:

学号 姓名 性别 出生日期
27 张三 2020-12-4

案例测试以下数据操作:

  1. 创建 students 索引和映射
  2. C - 创建学生数据
  3. R - 访问学生数据
  4. U - 修改学生数据
  5. D - 删除学生数据
  6. 使用 Repository 和 Criteria 搜索学生数据

创建项目

  1. 新建工程

新建 springboot module,添加 spring data elasticsearch 依赖

项目的 pom.xml 文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.6.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>cn.tedu</groupId><artifactId>es-springboot</artifactId><version>0.0.1-SNAPSHOT</version><name>es-springboot</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><exclusions><exclusion><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId></exclusion></exclusions></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

application.yml 配置

logging.level.tracer=TRACE 作用是在控制台中显示底层的查询日志

spring:elasticsearch:rest:uris: http://192.168.64.181:9200logging:level:tracer: TRACE

Student 实体类

package cn.tedu.esspringboot.es;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.DateFormat;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;@Document(indexName = "students",shards = 3,replicas = 2)
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {@Idprivate Long id;@Field(analyzer = "ngram",type = FieldType.Text)private String name;@Field(type = FieldType.Keyword)private Character gender;@Field(type= FieldType.Date,format = DateFormat.custom,pattern = "yyyy-M-d")private String birthDate;
}

@Document 注解

@Documnet注解对索引的参数进行设置。

上面代码中,把 students 索引的分片数设置为3,副本数设置为2。

@Id 注解

在 Elasticsearch 中创建文档时,使用 @Id 注解的字段作为文档的 _id 值

@Field 注解

通过 @Field 注解设置字段的数据类型和其他属性。

文本类型 text 和 keyword

text 类型会进行分词。

keyword 不会分词。

analyzer 指定分词器

通过 analyzer 设置可以指定分词器,例如 ik_smart、ik_max_word 等。

我们这个例子中,对学生姓名字段使用的分词器是 ngram 分词器,其分词效果如下面例子所示:

字符串 分词结果
刘德华
刘德
刘德华

德华

通过 ElasticsearchRepository 实现 CRUD 操作

Spring Data 的 Repository 接口提供了一种声明式的数据操作规范,无序编写任何代码,只需遵循 Spring Data 的方法定义规范即可完成数据的 CRUD 操作。

ElasticsearchRepository 继承自 Repository,其中已经预定义了基本的 CURD 方法,我们可以通过继承 ElasticsearchRepository,添加自定义的数据操作方法。

Repository 方法命名规范

自定义数据操作方法需要遵循 Repository 规范,示例如下:

关键词    方法名    es查询
And    findByNameAndPrice    { “query” : { “bool” : { “must” : [ { “query_string” : { “query” : “?”, “fields” : [ “name” ] } }, { “query_string” : { “query” : “?”, “fields” : [ “price” ] } } ] } }}
Or    findByNameOrPrice    { “query” : { “bool” : { “should” : [ { “query_string” : { “query” : “?”, “fields” : [ “name” ] } }, { “query_string” : { “query” : “?”, “fields” : [ “price” ] } } ] } }}
Is    findByName    { “query” : { “bool” : { “must” : [ { “query_string” : { “query” : “?”, “fields” : [ “name” ] } } ] } }}
Not    findByNameNot    { “query” : { “bool” : { “must_not” : [ { “query_string” : { “query” : “?”, “fields” : [ “name” ] } } ] } }}
Between    findByPriceBetween    { “query” : { “bool” : { “must” : [ {“range” : {“price” : {“from” : ?, “to” : ?, “include_lower” : true, “include_upper” : true } } } ] } }}
LessThan    findByPriceLessThan    { “query” : { “bool” : { “must” : [ {“range” : {“price” : {“from” : null, “to” : ?, “include_lower” : true, “include_upper” : false } } } ] } }}
LessThanEqual    findByPriceLessThanEqual    { “query” : { “bool” : { “must” : [ {“range” : {“price” : {“from” : null, “to” : ?, “include_lower” : true, “include_upper” : true } } } ] } }}
GreaterThan    findByPriceGreaterThan    { “query” : { “bool” : { “must” : [ {“range” : {“price” : {“from” : ?, “to” : null, “include_lower” : false, “include_upper” : true } } } ] } }}
GreaterThanEqual    findByPriceGreaterThan    { “query” : { “bool” : { “must” : [ {“range” : {“price” : {“from” : ?, “to” : null, “include_lower” : true, “include_upper” : true } } } ] } }}
Before    findByPriceBefore    { “query” : { “bool” : { “must” : [ {“range” : {“price” : {“from” : null, “to” : ?, “include_lower” : true, “include_upper” : true } } } ] } }}
After    findByPriceAfter    { “query” : { “bool” : { “must” : [ {“range” : {“price” : {“from” : ?, “to” : null, “include_lower” : true, “include_upper” : true } } } ] } }}
Like    findByNameLike    { “query” : { “bool” : { “must” : [ { “query_string” : { “query” : “?*”, “fields” : [ “name” ] }, “analyze_wildcard”: true } ] } }}
StartingWith    findByNameStartingWith    { “query” : { “bool” : { “must” : [ { “query_string” : { “query” : “?*”, “fields” : [ “name” ] }, “analyze_wildcard”: true } ] } }}
EndingWith    findByNameEndingWith    { “query” : { “bool” : { “must” : [ { “query_string” : { “query” : “*?”, “fields” : [ “name” ] }, “analyze_wildcard”: true } ] } }}
Contains/Containing    findByNameContaining    { “query” : { “bool” : { “must” : [ { “query_string” : { “query” : “?”, “fields” : [ “name” ] }, “analyze_wildcard”: true } ] } }}
In (when annotated as FieldType.Keyword)    findByNameIn(Collectionnames)    { “query” : { “bool” : { “must” : [ {“bool” : {“must” : [ {“terms” : {“name” : ["?","?"]}} ] } } ] } }}
In    findByNameIn(Collectionnames)    { “query”: {“bool”: {“must”: [{“query_string”:{“query”: “”?" “?”", “fields”: [“name”]}}]}}}
NotIn (when annotated as FieldType.Keyword)    findByNameNotIn(Collectionnames)    { “query” : { “bool” : { “must” : [ {“bool” : {“must_not” : [ {“terms” : {“name” : ["?","?"]}} ] } } ] } }}
NotIn    findByNameNotIn(Collectionnames)    {“query”: {“bool”: {“must”: [{“query_string”: {“query”: “NOT(”?" “?”)", “fields”: [“name”]}}]}}}
Near    findByStoreNear    Not Supported Yet !
True    findByAvailableTrue    { “query” : { “bool” : { “must” : [ { “query_string” : { “query” : “true”, “fields” : [ “available” ] } } ] } }}
False    findByAvailableFalse    { “query” : { “bool” : { “must” : [ { “query_string” : { “query” : “false”, “fields” : [ “available” ] } } ] } }}
OrderBy    findByAvailableTrueOrderByNameDesc    { “query” : { “bool” : { “must” : [ { “query_string” : { “query” : “true”, “fields” : [ “available” ] } } ] } }, “sort”:[{“name”:{“order”:“desc”}}] }

StudentRepository

package cn.tedu.esspringboot.es;import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import java.util.List;public interface StudentRepository extends ElasticsearchRepository<Student, Long> {List<Student> findByName(String name);List<Student> findByNameOrBirthDate(String name, String birthDate);
}

业务类 StudentService

package cn.tedu.esspringboot.es;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;@Service
public class StudentService {@Autowiredprivate StudentRepository studentRepo;public void save(Student student) {studentRepo.save(student);}public void delete(Long id) {studentRepo.deleteById(id);}public void update(Student student) {save(student);}public List<Student> findByName(String name) {return studentRepo.findByName(name);}public List<Student> findByNameOrBirthDate(String name, String birthDate) {return studentRepo.findByNameOrBirthDate(name, birthDate);}
}

在 Elasticsearch 中创建 students 索引

在开始运行测试之前,在 Elasticsearch 中先创建 students 索引:

PUT /students
{"settings": {"number_of_shards": 3,"number_of_replicas": 2,"index.max_ngram_diff":30,"analysis": {"analyzer": {"ngram_analyzer": {"tokenizer": "ngram_tokenizer"}},"tokenizer": {"ngram_tokenizer": {"type": "ngram","min_gram": 1,"max_gram": 30,"token_chars": ["letter","digit"]}}}},"mappings": {"properties": {"id": {"type": "long"},"name": {"type": "text","analyzer": "ngram_analyzer"},"gender": {"type": "keyword"},"birthDate": {"type": "date","format": "yyyy-MM-dd"}}}
}

测试学生数据的 CRUD 操作

添加测试类,对学生数据进行 CRUD 测试

package cn.tedu.esspringboot;import cn.tedu.esspringboot.es.Student;
import cn.tedu.esspringboot.es.StudentService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.util.List;@SpringBootTest
public class Test1 {@Autowiredprivate StudentService studentService;@Testpublic void test1() {studentService.save(new Student(998L,"张三",'男',"2020-12-04"));}@Testpublic void test2() {studentService.update(new Student(1L,"李四",'女',"2020-12-04"));}@Testpublic void test3() {List<Student> stu = studentService.findByName("四");System.out.println(stu);}@Testpublic void test4() throws Exception {List<Student> stu;stu = studentService.findByNameOrBirthDate("四", "1999-09-09");System.out.println(stu);stu = studentService.findByNameOrBirthDate("SFSDFS", "2020-12-04");System.out.println(stu);}
}

依次运行每个测试方法,并使用 head 观察测试结果

使用 Criteria 构建查询

Spring Data Elasticsearch 中,可以使用 SearchOperations 工具执行一些更复杂的查询,这些查询操作接收一个 Query 对象封装的查询操作。

Spring Data Elasticsearch 中的 Query 有三种:

  • CriteriaQuery
  • StringQuery
  • NativeSearchQuery

多数情况下,CriteriaQuery 都可以满足我们的查询求。下面来看两个 Criteria 查询示例:

StudentSearcher

package cn.tedu.esspringboot.es;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.Criteria;
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
import org.springframework.stereotype.Component;import java.util.List;
import java.util.stream.Collectors;@Component
public class StudentSearcher {@Autowiredprivate ElasticsearchOperations searchOperations;public List<Student> searchByBirthDate(String birthDate) {Criteria c = new Criteria("birthDate").is(birthDate);return criteriaSearch(c);}public List<Student> searchByBirthDate(String ge, String le) {Criteria c = new Criteria("birthDate").between(ge, le);return criteriaSearch(c);}private List<Student> criteriaSearch(Criteria c) {CriteriaQuery q = new CriteriaQuery(c);SearchHits<Student> hits = searchOperations.search(q, Student.class);List<Student> list = hits.stream().map(SearchHit::getContent).collect(Collectors.toList());return list;}
}

修改 StudentService

在 StudentService 中,调用 StudentSearcher,执行查询:

package cn.tedu.esspringboot.es;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;@Service
public class StudentService {@Autowiredprivate StudentRepository studentRepo;@Autowiredprivate StudentSearcher studentSearcher;public void save(Student student) {studentRepo.save(student);}public void delete(Long id) {studentRepo.deleteById(id);}public void update(Student student) {save(student);}public List<Student> findByName(String name) {return studentRepo.findByName(name);}public List<Student> findByNameOrBirthDate(String name, String birthDate) {return studentRepo.findByNameOrBirthDate(name, birthDate);}public List<Student> findByBirthDate(String birthDate) {return studentSearcher.searchByBirthDate(birthDate);}public List<Student> findByBirthDate(String ge, String le) {return studentSearcher.searchByBirthDate(ge, le);}
}

在测试类中添加测试方法

package cn.tedu.esspringboot;import cn.tedu.esspringboot.es.Student;
import cn.tedu.esspringboot.es.StudentService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.util.List;@SpringBootTest
public class Test1 {@Autowiredprivate StudentService studentService;@Testpublic void test1() {studentService.save(new Student(998L,"张三",'男',"2020-12-04"));}@Testpublic void test2() {studentService.update(new Student(1L,"李四",'女',"2020-12-04"));}@Testpublic void test3() {List<Student> stu = studentService.findByName("四");System.out.println(stu);}@Testpublic void test4() throws Exception {List<Student> stu;stu = studentService.findByNameOrBirthDate("四", "1999-09-09");System.out.println(stu);stu = studentService.findByNameOrBirthDate("SFSDFS", "2020-12-04");System.out.println(stu);}@Testpublic void test5() throws Exception {List<Student> stu;stu = studentService.findByBirthDate("2020-12-04");System.out.println(stu);}@Testpublic void test6() throws Exception {List<Student> stu;stu = studentService.findByBirthDate("2020-12-05", "2020-12-09");System.out.println(stu);}
}

Elasticsearch搜索引擎安装使用及Java中使用相关推荐

  1. ElasticSearch搜索引擎详解-持续更新中

    ElasticSearch搜索引擎详解 1. ElasticSearch概述 1.1 elasticsearch是什么 1.2 全文搜索引擎 1.3 elasticsearch and solr 1. ...

  2. ffmpeg安装及在java中的使用案例

    目录 前言 什么是ffmpeg? Windows下载及安装 后台代码 测试上传及播放 总结 前言 在开发中,经常有项目页面需要播放视频,也经常会有视频的容量很大,上次客户需要在页面上播放他们公司的宣传 ...

  3. ES(elasticsearch)搜索引擎安装和使用

    本文章为转载文章,如要转载标注出处 查看全文 http://www.taodudu.cc/news/show-3144290.html 相关文章: VT高级搜索语法 hive模糊搜索表 击溃360手机 ...

  4. ElasticSerach安装IK中文分词器,并在Java中使用

    1.所有文章优先发表在个人博客上: https://www.xdx97.com 2.后续如果有修改的话,可能忘记更新到CSDN了,给你带来不便,抱歉. 3.个人博客本篇文章地址 : https://w ...

  5. ElasticSearch在Java中的使用

    前言 ElasticSearch在Java中使用,在此感谢狂神老师,狂神大神ES课程 提示:以下是本篇文章正文内容,下面案例可供参考 一.ElasticSearch-head可视化界面安装 下载并且解 ...

  6. elasticsearch搜索引擎下载安装

    import com.yuepu.common.core.domain.BaseEntity; import lombok.Data;import java.util.Date; import jav ...

  7. elasticsearch搜索引擎查询java工具类

    Elasticsearch查询java工具类 项目组使用Elasticsearch搜索引擎也有一段时间了,刚开始是2.4版本,现在又要在新的工程中使用,准备升级为5.4版本,以前的工具类也不好用了,没 ...

  8. java中git使用教程_【教程】Git在Eclipse中的安装和基本使用

    一.安装 点击 Help->Install New Software->add 安装地址为:http://download.eclipse.org/egit/updates/ 选择插件 点 ...

  9. java安装_快速提示:Java中的ISO 8601持续时间

    java安装 许多开发人员都知道ISO 8601定义的日期和时间的交换格式. (例如2007-08-31T16:47 +00:00代表2007年8月31日UTC的16:47 ) 但是,并不是很知名(至 ...

  10. 在Ubuntu中安装及配置java

    描述:在Ubuntu16.04中配置jdk1.8 1. 下载jdk 下载地址:Java SE Development Kit 8 - Downloads - jdk8u301 (oracle.com) ...

最新文章

  1. DNS-sly:利用网络复杂性躲避审查
  2. vnc远程无法关闭窗口_无法启动远程桌面服务(VNC)[关闭]
  3. python中align_Python中如何自动化对齐?
  4. Hibernate 中的DetachedCriteria。
  5. POJ 2299 - Ultra-QuickSort BIT
  6. python权重初始值设置_pytorch自定义初始化权重的方法
  7. pythonwindow程序窗体操作_python操作Windows窗口程序
  8. php获取2次跳转之后的网址,爬虫:获取多次跳转后的页面url
  9. 蓝桥杯 算法提高 奥运会开幕式 deque
  10. acer软件保护卡怎么解除_外观精致性能强,配置丰富重量轻、宏碁(Acer)墨舞EX214轻薄笔记本 深度评测...
  11. 乌镇互联网大会:马化腾强势宣布,明年将推“VR微信”
  12. html好看的侧滑效果,H5 - 侧滑效果实现
  13. 服务器错误数字(代码)对照表
  14. openinstall与太平洋汽车达成合作
  15. 电竞英雄联盟数据API接口 - 【英雄联赛统计】API调用示例代码
  16. 数据结构——图书管理系统
  17. 测U盘实际容量 (缩水U盘、扩容盘、假U盘)
  18. 英雄联盟手游 lol手游内测资格申请,教大家申请体验资格
  19. 视频教程-C#LINQ查询技术-C#
  20. PI控制器的Matlab代码

热门文章

  1. html js点击下拉菜单代码,JavaScript下拉菜单功能实例代码
  2. 看漫画与动漫选他们吧,两款多源怪,再也不愁找不到了
  3. ITK VKT 安装-详细
  4. iMindMap手绘思维导图软件免费版
  5. 一份ERP系统总体解决方案
  6. cs透视源码c语言,CS--GO透视自瞄C++源码 CSGO C++源代码 参考学习!!!(CSGO C++ source code) - 下载 - 搜珍网...
  7. 汇编dos系统调用(输入输出篇)
  8. smartPrinter 安装时1722错误
  9. OFFICE文档转换到PDF的几种方法与转换效率和性能的简单比较
  10. 网优测试软件苹果手机,手机端网优测试软件详细介绍