1.ElasticSearch下载和安装
ElasticSearch是使用java开发的,且本版本的es需要的jdk版本要是1.8以上,所以安装ElasticSearch 之前保证JDK1.8+安装完毕,并正确的配置好JDK环境变量,否则启动ElasticSearch失败。
下载地址:https://www.elastic.co/cn/downloads/
历史版本下载:https://www.elastic.co/cn/downloads/past-releases/
官方下载地址: https://www.elastic.co/products/elasticsearch
1.服务器安装步骤
ElasticSearch分为Linux和Window版本,基于我们主要学习的是ElasticSearch的Java客户端的使用,所以我们课程中使用的是安装较为简便的Window版本,项目上线后,公司的运维人员会安装Linux版的ES供我们连接使用。
1:下载ES压缩包
2:启动ES服务端
3:安装ES的图形化界面插件客户端
3-1:先解压elasticsearch-head-master.zip
文件
3-2:把解压的内容复制到tomcat的webapps下的ROOT目录下(先把ROOT删除干净).
3-3:然后启动tomcat。bin/startup.bat
3-4: 打开浏览器,输入 http://localhost:8080
1.点击ElasticSearch下的目录的elasticsearch.bat启动,控制台显示的日志:
2.查看日志文件
启动后注意可能会出现JVM堆内存不够得错误,需要修改elasticsearch-6.6.2/config目录下的配置文件jvm.options
然后访问浏览器 http://localhost:9200
得到如下信息,说明安装成功了:
{
"name": "wahuAuA",
"cluster_name": "elasticsearch",
"cluster_uuid": "5KWqdwlsSj-ts0sYzhYV8g",
"version": {
"number": "6.6.2",
"build_flavor": "default",
"build_type": "zip",
"build_hash": "3bd3e59",
"build_date": "2019-03-06T15:16:26.864148Z",
"build_snapshot": false,
"lucene_version": "7.6.0",
"minimum_wire_compatibility_version": "5.6.0",
"minimum_index_compatibility_version": "5.0.0"
},
"tagline": "You Know, for Search"
}
2.客户端安装步骤
3:安装ES的图形化界面插件客户端
3-1:先解压elasticsearch-head-master.zip 文件
3-2:把解压的内容复制到tomcat的webapps下的ROOT目录下(先把ROOT删除干净).
3-3:然后启动tomcat。bin/startup.bat
3-4: 打开浏览器,输入 http://localhost:8081 (如果出现端口冲突,可以修改conf/server.xml中的端口为别的端口。)
访问成功连接ElasticSearch 会报一下错误
原因 Elasticsearch的客户端 跨域 访问 服务端产生跨域错误
解决办法
在Elasticsearch的配置文件添加跨域配置:
#跨域问题
http.cors.enabled: true
http.cors.allow-origin: "*"
小结:
宽口不同相互访问就会出现跨域得问题,需要在es服务/config/elasticsearch.yml 需要如下配置:
http.cors.enabled: true
http.cors.allow-origin: "*"
配置完记得重启
熟悉目录结构
配置文件目录
3.Kibana得安装
Kibana是一个针对ElasticSearch的开源分析及可视化平台,用来搜索、查看交互存储在Elasticsearch索引中的数据。使用Kibana ,可以通过各种图表进行高级数据分析及展示。Kibana让海量数据更容易理解。它操作简单,基于浏览器的用户界面可以快速创建仪表板( dashboard )实时显示Elasticsearch查询动态。设置Kibana非常简单。无需编码或者额外的基础架构,几分钟内就可以完成Kibana安装并启动Elasticsearch索引监测。
注意下载得版本需要与 ElasticSearch 对应
https://www.elastic.co/cn/downloads/
历史版本下载:https://www.elastic.co/cn/downloads/past-releases/
解压即可使用
进入bin目录
点击: kibana.bat
因为英文很菜, 所以说,我们对汉化
4.kibana汉化
编辑器打开kibana解压目录/config/kibana.yml(kibana-7.13.1-windows-x86_64/config/kibana.yml)
,添加
i18n.locale: "zh-CN"
设置后重启
5.IK分词器(elasticsearch插件)
分词:即把一段中文或者别的划分成一个个的关键字,我们在搜索时候会把自己的信息进行分词,会把数据库中或者索引库中的数据进行分词,然后进行一一个匹配操作,默认的中文分词是将每个字看成一个词(不使用用IK分词器的情况下),比如“我爱狂神”会被分为”我”,”爱”,”狂”,”神” ,这显然是不符合要求的,所以我们需要安装中文分词器ik来解决这个问题。
IK提供了两个分词算法: ik_smart和ik_max_word ,其中ik_smart为最少切分, ik_max_word为最细粒度划分!
下载地址 : https://github.com/medcl/elasticsearch-analysis-ik/releases
xioaguo文件夹是自己创建得
解压ik把里面得文件复制到小果文件夹中即可
重启ElasticSearch
5.使用kibana测试
ik_smart:最少拆分
ik_max_word
:最细粒度划分(穷尽词库的可能)
从上面看我们感觉分词都比较正常但是大多数得分词都满足不了我们
6.添加自定义ik分词到字典中
ik分词器提供了两种算法
ik_smart //最少切分
ik_max_word //最细粒度切分。
分词成功
.ElasticSearch简介
Lucene和ElasticSearch的关系:
- ElasticSearch是基于Lucene 做了一下封装和增强
官网 https://www.elastic.co/cn/downloads/elasticsearch
1.什么是ElasticSearch
Elaticsearch,简称为es,es是一个开源的高扩展的分布式全文搜索服务,它可以近乎实时的存储、检索数据;本身扩展性很好,可以扩展到上百台服务器,处理PB级别的数据。es也是使用Java开发并使用Lucene作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的RESTful API来隐藏Lucene的复杂性,从而让全文搜索变得简单。
2.ElasticSearch使用案例
- 2013年初,GitHub抛弃了Solr,采取ElasticSearch来做PB级的搜索。“GitHub使用ElasticSearch搜索20TB的数据,包括13亿文件和1300亿行代码”。
- 新浪使用ES,分析处理32亿条实时日志
- 阿里使用ES 构建挖财自己得日志采集和分析体系
- 电商网站,检索商品
- 日志数据分析, logstash采集日志, ES进行复杂的数据分析, ELK技术, elasticsearch+logstash+kibana
- 百度百科,全文检索,高亮,搜索推荐
3.ElasticSearch对比Solr
- Solr利用 Zookeeper 进行分布式管理,而 Elasticsearch 自身带有分布式协调管理功能。
- Solr支持更多格式的数据,而Elasticsearch仅支持json文件格式
- Solr官方提供的功能更多,而Elasticsearch本身更注重于核心功能,高级功能都有第三方插件提供。
- Solr在传统的搜索应用中表现好于Elasticsearch,但在处理实时搜索应用时效率明显低于 Elasticsearch当单纯的对已有数据进行搜索时,Solr更快,当实时建立索引时, Solr会产生io阻塞,查询性能较差, Elasticsearch具有明显的优势。随着数据量的增加,Solr的搜索效率会变得更低,而Elasticsearch却没有明显的变化。综上所述,Solr的架构不适合实时搜索的应用。Solr是传统搜索应用的有力解决方案,但 Elasticsearch 更适用于新兴的实时搜索应用。
总结
- es基本开箱即用(解压就可以使用)非常简单
- Solr 利用Zookeeper进行分布式管理,而Elasticsearch 自身带有分布式协调管理功能** 。
- 、Solr 支持更多格式的数据,比如JSON、XML、 CSV ,而Elasticsearch仅支持json文件格式。
- Solr 官方提供的功能更多,而Elasticsearch本身更注重于核心功能,高级功能多有第三方插件提供,例如图形化界面需要kibana友好支撑
- Solr 查询快,但更新索引时慢(即插入删除慢) ,用于电商等查询多的应用;
- ES建立索引快(即查询慢) ,即实时性查询快,用于facebook新浪等搜索。
- Solr是传统搜索应用的有力解决方案,但Elasticsearch更适用于新兴的实时搜索应用。
3.ElasticSearch:核心概念
ElasticSearch是面向文档,关系行数据库和ElasticSearch客观对比!一切都是JSON!
Elasticsearch面向文档(document oriented)的,这意味着它可以存储整个对象或文档(document)。然而它不仅仅是存储,还会索引(index)每个文档的内容使之可以被搜索。在Elasticsearch中,你可以对文档进行索引、搜索、排序、过滤。
Mysql关系型数据库 | ElasticSearch服务 |
---|---|
数据库(database) | 索引(indices) |
表(tabes) | types(慢慢会被弃用) |
行(rows) | 文档(documents) |
字段(columes) | 字段(fields) |
-
进实时 (速度快)
ElasticSearch是一个接近实时的搜索平台。这意味着,从索引一个文档直到这个文档能够被搜索到有一个轻微的延迟(通常是1秒以内)
-
集群 cluster
一个集群就是由一个或多个节点组织在一起,它们共同持有整个的数据,并一起提供索引和搜索功能。一个集群由一个唯一的名字标识,==这个名字默认就是“elasticsearch”。==这个名字是重要的,因为一个节点只能通过指定某个集群的名字,来加入这个集群。
-
节点
一个节点是集群中的一个服务器,作为集群的一部分,它存储数据,参与集群的索引和搜索功能。和集群类似,一个节点也是由一个名字来标识的,默认情况下,这个名字是一个随机的漫威漫画角色的名字,这个名字会在启动的时候赋予节点。这个名字对于管理工作来说挺重要的,因为在这个管理过程中,你会去确定网络中的哪些服务器对应于Elasticsearch集群中的哪些节点。 一个节点可以通过配置集群名称的方式来加入一个指定的集群。默认情况下,每个节点都会被安排加入到一个叫 做“elasticsearch”的集群中,这意味着,如果你在你的网络中启动了若干个节点,并假定它们能够相互发现彼此, 它们将会自动地形成并加入到一个叫做“elasticsearch”的集群中。 在一个集群里,只要你想,可以拥有任意多个节点。而且,如果当前你的网络中没有运行任何Elasticsearch节点, 这时启动一个节点,会默认创建并加入一个叫做“elasticsearch”的集群。
-
**索引 ** index(重点) 索引库
- 几分相似特征的文档的集合。比如说,你可以有一个客户数据的索引,另一个产品目录的索引,还有一个订单数据的索引。一个索引由一个名字来标识(必须全部是小写字母的),并且当我们要对对应于这个索引中的文档进行索引、搜索、更新和删除的时候,都要使用到这个名字。在一个集群中,可以定义任意多的索引。
- 一个索引就是一个拥有几分相似特征的文档的集合。比如说,你可以有一个客户数据的索引,另一个产品目录的索引,还有一个订单数据的索引。一个索引由一个名字来标识(必须全部是小写字母的),并且当我们要对对应于这个索引中的文档进行索引、搜索、更新和删除的时候,都要使用到这个名字。在一个集群中,可以定义任意多的索引。
-
类型type(重点)
在一个索引中,你只能定义一种类型。一个类型是你的索引的一个逻辑上的分类/分区,其语义完全由你来定。通常,会为具有一组共同字段的文档定义一个类型。比如说,我们假设你运营一个博客平台并且将你所有的数据存储到一个索引中。在这个索引中,你可以为用户数据定义一个类型,为博客数据定义另一个类型,当然,也可以为评论数据定义另一个类型。
-
文档(重点)
一个文档是一个可被索引的基础信息单元。比如,你可以拥有某一个客户的文档,某一个产品的一个文档,当然,也可以拥有某个订单的一个文档。文档以JSON(Javascript Object Notation)格式来表示,而JSON是一个到处存在的互联网数据交互格式。 在一个index/type里面,你可以存储任意多的文档。注意,尽管一个文档,物理上存在于一个索引之中,文档必须 被索引/赋予一个索引的type。
-
分片和复制shards&replicas–自我、修复、备份
一个索引可以存储超出单个节点硬件限制的大量数据。比如,一个具有10亿文档的索引占据1TB的磁盘空间,而任一节点都没有这样大的磁盘空间;或者单个节点处理搜索请求,响应太慢。为了解决这个问题,Elasticsearch提供了将索引划分成多份的能力,这些份就叫做分片。当你创建一个索引的时候,你可以指定你想要的分片的数量。每个分片本身也是一个功能完善并且独立的“索引”,这个“索引”可以被放置到集群中的任何节点上。分片很重要,主要有两方面的原因:
- 允许你水平分割/扩展你的内容容量。
- 允许你在分片(潜在地,位于多个节点上)之上进行分布式的、并行的操作,进而提高性能/吞吐量。至于一个分片怎样分布,它的文档怎样聚合回搜索请求,是完全由Elasticsearch管理的,对于作为用户的你来说,这些都是透明的。在一个网络/云的环境里,失败随时都可能发生,在某个分片/节点不知怎么的就处于离线状态,或者由于任何原因消失了,这种情况下,有一个故障转移机制是非常有用并且是强烈推荐的。为此目的,Elasticsearch允许你创建分片的一份或多份拷贝,这些拷贝叫做复制分片,或者直接叫复制。复制之所以重要,有两个主要原因: 在分片/节点失败的情况下,提供了高可用性。因为这个原因,注意到复制分片从不与原/主要(original/primary)分片置于同一节点上是非常重要的。扩展你的搜索量/吞吐量,因为搜索可以在所有的复制上并行运行。总之,每个索引可以被分成多个分片。一个索引也可以被复制0次(意思是没有复制)或多次。一旦复制了,每个索引就有了主分片(作为复制源的原来的分片)和复制分片(主分片的拷贝)之别。分片和复制的数量可以在索引创建的时候指定。在索引创建之后,你可以在任何时候动态地改变复制的数量,但是你事后不能改变分片的数量。默认情况下,Elasticsearch中的每个索引被分片5个主分片和1个复制,这意味着,如果你的集群中至少有两个节点,你的索引将会有5个主分片和另外5个复制分片(1个完全拷贝),这样的话每个索引总共就有10个分片。
-
映射 mapping(重点)
mapping是处理数据的方式和规则方面做一些限制,如某个字段的数据类型、默认值、分析器、是否被索引等等,这些都是映射里面可以设置的,其它就是处理es里面数据的一些使用规则设置也叫做映射,按着最优规则处理数据对性能提高很大,因此才需要建立映射,并且需要思考如何建立映射才能对性能更好?和建立表结构表关系数据库三范式类似。【是否分词、是否索引、是否存储】
小结:
-
什么是集群
-
给所有的es节点,定义一个相同的名字: 默认名字是elasticsearch,就可以自动转换成集群。
-
什么是节点
每一个es服务就是一个节点。只要节点名字不相同,就可以形成一个集群。
-
什么是索引(Indices)(重点)
一个索引就是一个拥有相似特征的文档的集合,(足够灵活。数据结构可以不一样)。
-
什么是类型(Types)(重点)
类型数据的表,进行文档的区分。
-
什么是文档(Document)(重点)
数据存储的结构,数据结构:json
-
什么是映射(Mapping)
是定义文档数据结构的属性的规范。比如属性:是否要存储,是否要索引,采用什么样的分词等。
-
4.Rest风格说明
一种软件架构风格,而不是标准,只提供了一组设置原则和约束条件,他主要用于客户端和服务器交互得软件,基于这个风格设计得软件可以更简洁,更有层次,更易于实现缓存等机制
method | url地址 | 描述 |
---|---|---|
PUT(创建,修改) | localhost:9200/索引名称/类型名称/文档id | 创建文档,(指定文档id) |
POST(创建) | localhost:9200/索引名称/类型名称 | 创建文档(随机文档id) |
POST(修改) | localhost:9200/索引名称/类型名称/文档id/_update | 修改文档 |
DELETE(删除) | localhost:9200/索引名称/类型名称/文档id | 删除文档 |
GET(查询) | localhost:9200/索引名称/类型名称/文档id | 查询文档通过文档ID |
POST(查询) | localhost:9200/索引名称/类型名称/文档id/_search | 查询所有数据 |
1.创建索引
PUT /test/type/1
{
"name" : "我是行健乖乖霸",
"age" : 18
}
添加索引成功
2.字段类型
- 字符串类型
- text ,keyword
- text:支持分词,全文检索,支持模糊、精确查询,不支持聚合,排序操作;text类型的最大支持的字符长度无限制,适合大字段存储;
- keyword:不进行分词,直接索引、支持模糊、支持精确匹配,支持聚合、排序操作。keyword类型的最大支持的长度为——32766个UTF-8类型的字符,可以通过设置ignore_above指定自持字符长度,超过给定长度后的数据将不被索引,无法通过term精确匹配检索返回结果。
- 数值类型
- long、Integer、short、byte、double、float、half float、scaled float
- 日期类型
- date
- 布尔类型
- boolean
- 等等。。。
3.获取其他得信息
GET _cat/indices
GET _cat/aliases
GET _cat/allocation
GET _cat/count
GET _cat/fielddata
GET _cat/health
GET _cat/indices
GET _cat/master
GET _cat/nodeattrs
GET _cat/nodes
GET _cat/pending_tasks
GET _cat/plugins
GET _cat/recovery
GET _cat/repositories
GET _cat/segments
GET _cat/shards
GET _cat/snapshots
GET _cat/tasks
GET _cat/templates
GET _cat/thread_pool
4.创建规则
PUT /test3/_doc/1
{
"name" : "行健",
"age":18,
"birth":"1998-10-10"
}
5.获取规则
GET test3/_doc/1
6.修改规则
两种方案
1.使用(put覆盖原来得得值)
- 版本加 1 (_version)
- 缺点,就是如果某个字段漏掉没有写,那么更新是没有写得字段,没有得会覆盖
PUT /test3/_doc/1
{
"name" : "行健",
"age":20,
"birth":"1998-10-10"
}
PUT /test3/_doc/1
{
"name" : "行健"
}
2.使用(post)
②新的(使用post的update)
- version不会改变
- 需要注意doc
不会丢失字段
POST /test3/_doc/1/_update
{
"doc": {
"name":"post修改了版本不会增加",
"age" : 3
}
}
GET /test3/_doc/1
7.删除规则
DELETE /test //删除索引
GET /test
DELETE /test3/_doc/1 //删除文档 根据id删除
GET /test3/_doc/1
5.测试环境搭建
1.创建索引
1.创建工程
2.添加依赖
<dependencies>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
<version>6.6.2</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.9.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
3.添加日志文件‘
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%m%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="INFO">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
4.测试代码
/*
*创建索引
* */
@Test
public void show1() throws Exception{
// + 创建Settings配置信息对象
Settings builder = Settings.builder().
// 参数一: 集群key (固定不变)
// 参数二:集群环境名称,默认的ES的环境集群名称为 "elasticsearch"
put("cluster.name","elasticsearch").build();
// + 创建ES传输客户端对象
PreBuiltTransportClient client = new PreBuiltTransportClient(builder);
client.addTransportAddress(new TransportAddress(InetAddress.getByName("127.0.0.1"), 9300));
// + 使用传输客户端对象创建索引库
client.admin().indices().prepareCreate("blog").get();
// + 释放资源
client.close();
}
2.添加文档
1.第一种方式
- 创建Settings配置信息对象
- 创建ES传输客户端对象
- 创建文档对象,创建一个json格式的字符串,或者使用XContentBuilder
- 传输客户端对象把文档添加到索引库中
- 释放资源
代码如下
/*
* 添加文档
* */
@Test
public void show2() throws IOException {
//创建Settings配置信息
Settings build = Settings.builder()
.put("cluster.name", "elasticsearch").build();
//创建ES传输客户端对象
PreBuiltTransportClient client = new PreBuiltTransportClient(build);
//添加传输对象
client.addTransportAddress(
new TransportAddress(InetAddress.getByName("127.0.0.1"),9300));
//创建内容构建对象
XContentBuilder builder = XContentFactory.jsonBuilder()
.startObject()
.field("id",1)
.field("title","elasticsearch搜索服务")
.field("content","ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎。")
.endObject();
client.prepareIndex("blog","article","1")
.setSource(builder).get();//执行请求
// 释放资源
client.close();
2.第二种方式 (重要)
步骤1 2 是不是重复造轮子
所以我们把他进行封装
package com.xjggb.utis;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class ElasticSearchUtis {
private static Settings settings;
private static TransportClient transportClient;
static {
// 1. 创建Settings配置信息对象
settings = Settings.builder()
.put("cluster.name", "elasticsearch").build();
// 2. 创建ES传输客户端对象
transportClient = new PreBuiltTransportClient(settings);
}
public static TransportClient getTransportClient() throws UnknownHostException {
transportClient.addTransportAddress(new TransportAddress(
InetAddress.getByName("127.0.0.1"), 9300));
return transportClient;
}
}
编程步骤
- 创建Settings配置信息对象
- 创建ES传输客户端对象
- 创建Mmap集合,封装数据
- 传输酷虎端对象把文档添加到索引库种
- 释放资源
代码如下
@Test
public void show3() throws UnknownHostException {
// 获取传输对象
TransportClient transportClient = ElasticSearchUtis.getTransportClient();
// 定义map集合封装文档
HashMap<String, Object> map = new HashMap<>();
map.put("id",2);
map.put("title", "dubbo分布式服务框架");
map.put("content", "dubbo阿里巴巴开源的高性能的RPC框架。");
//添加文档
transportClient.prepareIndex("blog","article", "2")
.setSource(map).get();
//释放资源
transportClient.close();
}
3.第三种方式(重要)
添加jackson依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.6</version>
</dependency>
编程步骤
- 获取ES连接客户端对象
- 创建entity对象,封装文档数据
- 将实体类转换为json数据
- 传输客户端对象,把文档添加到索引库中
- 释放资源
/*
* 创建文档:第三种方式
* */
@Test
public void show4() throws UnknownHostException, JsonProcessingException {
//创建es连接传输客户端对象
TransportClient transportClient =
ElasticSearchUtis.getTransportClient();
//创建实体对象
User user = new User();
user.setId(5);
user.setTitle("lucene全文检索框架");
user.setContent("lucene是开源的全文检索框架");
// 把对象转换成json字符串‘
String json = new ObjectMapper().writeValueAsString(user);
//添加文档
transportClient.prepareIndex("blog","article")
.setSource(json, XContentType.JSON).get();
//释放资源
transportClient.close();
}
4.批量添加文档
- 获取es传输客户端对象
- 创建批量的请求构建对象
- 批量的请求构建对象,循环内添加 索引请求对象
- 批量请求构建对象提交请求
- 释放资源
/*
* 批量的添加文档
* */
@Test
public void show5() throws Exception {
//获取es客户端传输对象
TransportClient transportClient = ElasticSearchUtis.getTransportClient();
//创建批量请求构建对象
BulkRequestBuilder bulk = transportClient.prepareBulk();
// 获取当前时间
long l = System.currentTimeMillis();
for (long i = 1; i <= 1000; i++) {
User article = new User();
article.setId(i);
article.setTitle("dubbo分布式服务框架" + i);
article.setContent("dubbo阿里巴巴开源的高性能的RPC框架" + i);
//创建索引对象
IndexRequest source = new IndexRequest("blog", "article", i + "")
.source(new ObjectMapper().writeValueAsString(article),
XContentType.JSON);
bulk.add(source);
}
//提交请求
bulk.get();
long l1 = System.currentTimeMillis();
System.out.println("运行的毫秒数" + (l1-l));
//毫秒数为1010
//释放资源
transportClient.close();
}
5.修改文档
开发步骤
- 获取es传输客户端对象
- 把实体对象转换成json字符串
- 传输客户端对象修改文档索引库
- 释放资源
/*
* 修改文档
* */
@Test
public void show() throws Exception {
// 获取es连接客户端
TransportClient transportClient = ElasticSearchUtis.getTransportClient();
// 创建用户对象
User user = new User();
user.setId(1);
user.setTitle("lucene全文检索修改了");
user.setContent("lucene是apache组织开源的全文检索框架。");
String jsonStr = new ObjectMapper().writeValueAsString(user);
// 修改文档
transportClient.prepareUpdate("blog","article","1")
.setDoc(jsonStr,XContentType.JSON).get();
// 释放资源
transportClient.close();
}
6.删除文档
开发步骤
- 获得es客户端连接对象
- 传输客户端对象删除文档
- 释放资源
/*
* 删除文档
* */
@Test
public void show6() throws Exception {
// 获取es客户端连接对象
TransportClient transportClient = ElasticSearchUtis.getTransportClient();
//删除文档
transportClient.prepareDelete("blog","article","1")
.get();
//释放资源
transportClient.close();
}
3.索引删除
开发步骤
- 获取es传输客户端对象
- 删除索引库
- 释放资源
- ’
代码如下
/*
* 删除索引库
* */
@Test
public void show7() throws Exception {
//获取esc传输客户端对象
TransportClient transportClient = ElasticSearchUtis.getTransportClient();
//删除索引库
transportClient.admin().indices().prepareDelete("blog")
.get();
//释放资源
transportClient.close();
}
6.创建映射
Mapping就是定义Document中的每个Field的特征(数据类型,是否存储,是否索引,是否分词等)
-
类型名称: 就是前面讲的type的概念,类似于数据库中的表。
-
字段名: 任意填写,可以指定许多属性,例如
- type:类型,可以是text、long、short、date、integer、object等
- index:是否索引,默认为true
- store:是否存储,默认为false
- analyzer:分词器,这里的ik_max_word即使用ik分词器
ik分词的两种算法
ik_smart //最少切分
ik_max_word //最细粒度切分
开发步骤
- 获得es传输客户端
- 创建索引库管理客户端,创建空的索引库
- 创建映射信息 json格式字符串,使用XContentBuilder
- 创建映射请求对象,封装请求信息
- 索引库管理客户端,为索引库添加映射
- 释放资源
代码如下
/*
* 创建映射
* */
@Test
public void show8() throws Exception {
// 获取es传输客户端对象
TransportClient transportClient = ElasticSearchUtis.getTransportClient();
// 创建索引库管理客户端
IndicesAdminClient indices = transportClient.admin().indices();
// 创建空的索引库
indices.prepareCreate("blog2").get();
// 创建映射信息json格式字符串XContentFactory
XContentBuilder builder = XContentFactory.jsonBuilder();
builder.startObject()
.startObject("article")
.startObject("properties");
builder.startObject("id")
.field("type", "long")
.field("store", true)
.endObject();
builder.startObject("title")
.field("type", "text") //类型
.field("store", true) //是否存储
.field("analyzer", "ik_smart") //设置分词器
.endObject();
builder.startObject("content")
.field("type", "text")
.field("store", true)
.field("analyzer","ik_max_word")
.endObject();
builder.endObject();
builder.endObject();
builder.endObject();
// 创建映射请求对象,封装信息
PutMappingRequest putMappingRequest = new PutMappingRequest("blog2")
.type("article").source(builder);
// 索引库管理客户端
indices.putMapping(putMappingRequest).get();
// 释放资源
transportClient.close();
}
7.高级查询
1.全部查询
/*
* 匹配查询全部数据
* */
@Test
public void show9() throws Exception {
//获取es传输客户端对象
TransportClient transportClient = ElasticSearchUtis.getTransportClient();
//创建收索请求构建对象
SearchRequestBuilder searchRequestBuilder = transportClient
.prepareSearch("blog2").setTypes("article");
// 设置查询条件(匹配全部)
searchRequestBuilder.setQuery(QueryBuilders.matchAllQuery());
// 执行请求 得到收索响应对象
SearchResponse searchResponse = searchRequestBuilder.get();
// 获取收索结果
SearchHits hits = searchResponse.getHits();
System.out.println("命中的数量" + hits.getTotalHits());
for (SearchHit hit : hits) {
System.out.println("JSON字符串:" + hit.getSourceAsString());
System.out.println("id: " + hit.getSourceAsMap().get("id"));
System.out.println("title: " + hit.getSourceAsMap().get("title"));
System.out.println("content: " + hit.getSourceAsMap().get("content"));
}
//释放资源
transportClient.close();
}
2.字符串查询
/*
* 字符串查询数据
* */
@Test
public void show10() throws Exception {
//获取es传输客户端对象
TransportClient transportClient = ElasticSearchUtis.getTransportClient();
//创建收索请求构建对象
SearchRequestBuilder searchRequestBuilder = transportClient
.prepareSearch("blog2").setTypes("article");
// 设置查询条件(匹配全部)
searchRequestBuilder.setQuery(QueryBuilders.queryStringQuery("收服务"));
// 执行请求 得到收索响应对象
SearchResponse searchResponse = searchRequestBuilder.get();
// 获取收索结果
SearchHits hits = searchResponse.getHits();
System.out.println("命中的数量" + hits.getTotalHits());
for (SearchHit hit : hits) {
System.out.println("JSON字符串:" + hit.getSourceAsString());
System.out.println("id: " + hit.getSourceAsMap().get("id"));
System.out.println("title: " + hit.getSourceAsMap().get("title"));
System.out.println("content: " + hit.getSourceAsMap().get("content"));
}
//释放资源
transportClient.close();
}
3.词条查询
/*
* 词条查询查询数据
* */
@Test
public void show11() throws Exception {
//获取es传输客户端对象
TransportClient transportClient = ElasticSearchUtis.getTransportClient();
//创建收索请求构建对象
SearchRequestBuilder searchRequestBuilder = transportClient
.prepareSearch("blog2").setTypes("article");
searchRequestBuilder.setQuery(QueryBuilders.termQuery("content","阿里巴巴"));
// 执行请求 得到收索响应对象
SearchResponse searchResponse = searchRequestBuilder.get();
// 获取收索结果
SearchHits hits = searchResponse.getHits();
System.out.println("命中的数量" + hits.getTotalHits());
for (SearchHit hit : hits) {
System.out.println("JSON字符串:" + hit.getSourceAsString());
System.out.println("id: " + hit.getSourceAsMap().get("id"));
System.out.println("title: " + hit.getSourceAsMap().get("title"));
System.out.println("content: " + hit.getSourceAsMap().get("content"));
}
//释放资源
transportClient.close();
}
4.根据id查询
/*
* 根据id查询
* */
@Test
public void show12() throws Exception {
//获取es传输客户端对象
TransportClient transportClient = ElasticSearchUtis.getTransportClient();
//创建收索请求构建对象
SearchRequestBuilder searchRequestBuilder = transportClient
.prepareSearch("blog2").setTypes("article");
// 这个id是索引的 _id
searchRequestBuilder.setQuery(QueryBuilders.idsQuery().addIds("2" ,"3"));
// 执行请求 得到收索响应对象
SearchResponse searchResponse = searchRequestBuilder.get();
// 获取收索结果
SearchHits hits = searchResponse.getHits();
System.out.println("命中的数量" + hits.getTotalHits());
for (SearchHit hit : hits) {
System.out.println("JSON字符串:" + hit.getSourceAsString());
System.out.println("id: " + hit.getSourceAsMap().get("id"));
System.out.println("title: " + hit.getSourceAsMap().get("title"));
System.out.println("content: " + hit.getSourceAsMap().get("content"));
}
//释放资源
transportClient.close();
}
5.范围查询
/*
* 范围查询
* */
@Test
public void show113() throws Exception {
//获取es传输客户端对象
TransportClient transportClient = ElasticSearchUtis.getTransportClient();
//创建收索请求构建对象
SearchRequestBuilder searchRequestBuilder = transportClient
.prepareSearch("blog2").setTypes("article");
// 设置范围查询,,根据拿着字段来设定范围
searchRequestBuilder.setQuery(QueryBuilders.rangeQuery("id")
.from(1,false) // 开始 不包含1
.to(3,false) // 结束 不包含3
// .from(1) //开始
// .to(3) // 结束
);
// 执行请求 得到收索响应对象
SearchResponse searchResponse = searchRequestBuilder.get();
// 获取收索结果
SearchHits hits = searchResponse.getHits();
System.out.println("命中的数量" + hits.getTotalHits());
for (SearchHit hit : hits) {
System.out.println("JSON字符串:" + hit.getSourceAsString());
System.out.println("id: " + hit.getSourceAsMap().get("id"));
System.out.println("title: " + hit.getSourceAsMap().get("title"));
System.out.println("content: " + hit.getSourceAsMap().get("content"));
}
//释放资源
transportClient.close();
}
6.分页和排序
/*
* 分页和排序
* */
@Test
public void show13() throws Exception {
//获取es传输客户端对象
TransportClient transportClient = ElasticSearchUtis.getTransportClient();
//创建收索请求构建对象
SearchRequestBuilder searchRequestBuilder = transportClient
.prepareSearch("blog2").setTypes("article");
// 设置范围查询,,根据拿着字段来设定范围
searchRequestBuilder.setQuery(QueryBuilders.matchQuery("title","服务框架"));
// 设置分页起始数 (当前页码-1) *夜大小
searchRequestBuilder.setFrom(0);
// 设置页大小
searchRequestBuilder.setSize(2);
// 设置排序 *(降序)
searchRequestBuilder.addSort("id", SortOrder.DESC);
// 执行请求 得到收索响应对象
SearchResponse searchResponse = searchRequestBuilder.get();
// 获取收索结果
SearchHits hits = searchResponse.getHits();
System.out.println("命中的数量" + hits.getTotalHits());
for (SearchHit hit : hits) {
System.out.println("JSON字符串:" + hit.getSourceAsString());
System.out.println("id: " + hit.getSourceAsMap().get("id"));
System.out.println("title: " + hit.getSourceAsMap().get("title"));
System.out.println("content: " + hit.getSourceAsMap().get("content"));
}
//释放资源
transportClient.close();
}
7.高亮显示
/*
* 高亮显示
* */
@Test
public void show14() throws Exception {
//获取es传输客户端对象
TransportClient transportClient = ElasticSearchUtis.getTransportClient();
//创建收索请求构建对象
SearchRequestBuilder searchRequestBuilder = transportClient
.prepareSearch("blog2").setTypes("article");
// 设置查询条件
searchRequestBuilder.setQuery(QueryBuilders.termQuery("content","框架"));
// 创建高亮对象
HighlightBuilder highlightBuilder = new HighlightBuilder();
// 设置高亮字段
highlightBuilder.field("content");
// 设置高亮前缀
highlightBuilder.preTags("<font color='red'>");
// 设置高亮对象
searchRequestBuilder.highlighter(highlightBuilder);
// 设置后缀
highlightBuilder.postTags("</font>");
// 执行请求 得到收索响应对象
SearchResponse searchResponse = searchRequestBuilder.get();
// 获取收索结果
SearchHits hits = searchResponse.getHits();
System.out.println("命中的数量" + hits.getTotalHits());
for (SearchHit hit : hits) {
// 获取高亮字段集合
Map<String, HighlightField> highlightFields = hit.getHighlightFields();
// 获取content字段的高亮内容
String content = highlightFields.get("content")
.getFragments()[0].toString();
System.out.println(hit.getSourceAsMap().get("id") + "\t"
+ hit.getSourceAsMap().get("title") + "\t" + content);
}
//释放资源
transportClient.close();
}
8.总结
- es的安装与启动
- es的索引库创建
- es添加文档
- es修改文档
- es删除文档
- es创建映射
- es查询
- 匹配全部查询
- 词条查询
- 根据id查询
- 范围查询
- 分页查询
- 高亮查询
9.SpringBoot集成 Elasticsearch
参考原文
原文链接:https://blog.csdn.net/weixin_43814195/article/details/85281287
1.SpringBootDataElasticsearchr入门
特征:
支持Spring的基于@Configuration的java配置方式,或者XML配置方式
提供了用于操作ES的便捷工具类ElasticsearchTemplate。包括实现文档到POJO之间的自动智能映射。
利用Spring的数据转换服务实现的功能丰富的对象映射
基于注解的元数据映射方式,而且可扩展以支持更多不同的数据格式
根据持久层接口自动生成对应实现方法,无需人工编写基本操作代码(类似mybatis,根据接口自动得到实现)。当然,也支持人工定制查询
1.创建工程 添加依赖
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>es-boot</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>es-boot</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>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2.添加配置文件
server:
port: 9004
spring:
data:
elasticsearch:
cluster-nodes: 127.0.0.1:9300
cluster-name: elasticsearch
3.索引操作
准备好实体类
public class Item {
private Long id;
private String title; //标题
private String category;// 分类
private String brand; // 品牌
private Double price; // 价格
private String images; // 图片地址
}
注解映射
Spring Data通过注解来声明字段的映射属性,有下面的三个注解:
@Document 作用在类,标记实体类为文档对象,一般有两个属性
indexName:对应索引库名称
type:对应在索引库中的类型
shards:分片数量,默认5
replicas:副本数量,默认1
@Id 作用在成员变量,标记一个字段作为id主键
@Field 作用在成员变量,标记为文档的字段,并指定字段映射属性:
type:字段类型,是枚举:FieldType,可以是text、long、short、date、integer、object等
text:存储数据时候,会自动分词,并生成索引
keyword:存储数据时候,不会分词建立索引
Numerical:数值类型,分两类
基本数据类型:long、interger、short、byte、double、float、half_float
浮点数的高精度类型:scaled_float
需要指定一个精度因子,比如10或100。elasticsearch会把真实值乘以这个因子后存储,取出时再还原。
Date:日期类型
elasticsearch可以对日期格式化为字符串存储,但是建议我们存储为毫秒值,存储为long,节省空间。
index:是否索引,布尔类型,默认是true
store:是否存储,布尔类型,默认是false
analyzer:分词器名称,这里的ik_max_word即使用ik分词器
@Document(indexName = "item",type = "docs", shards = 1, replicas = 0)
public class Item {
@Id
private Long id;
@Field(type = FieldType.Text, analyzer = "ik_max_word")
private String title; //标题
@Field(type = FieldType.Keyword)
private String category;// 分类
@Field(type = FieldType.Keyword)
private String brand; // 品牌
@Field(type = FieldType.Double)
private Double price; // 价格
@Field(index = false, type = FieldType.Keyword)
private String images; // 图片地址
}
4.创建索引
/*
* 添加索引
* */
@GetMapping("hello")
public void show(){
//创建索引会会根据Item类的@Document注解信息来创建
elasticsearchTemplate.createIndex(Item.class);
//配置映射,会根据Item类中的id,field等字自动完成映射
elasticsearchTemplate.putMapping(Item.class);
}
5.删除索引
/*
* 删除索引
* */
public void deleteIndex(){
// 根据类名删除
elasticsearchTemplate.deleteIndex(Item.class);
// 根据索引名删除
elasticsearchTemplate.deleteIndex("item");
}
6.新增文档数据
Spring Data的强大之处,就是在于你不用写任何的DAO处理,自动的根据方法名或者类的信息进行CRUD操作,只要你定义接口, 然后继承Repository提供的一些子接口,就能具备各种基本的CRUD功能。
所以我们继承接口就行了
public interface ItemMapper extends ElasticsearchRepository<Item,Long>{
}
新增对象代码如下
/*
* 添加数据
* */
@GetMapping("save")
public void save() {
Item item = new Item();
item.setId(1L);
item.setBrand("小米手机");
item.setCategory("手机");
item.setPrice(3499.00);
item.setTitle("小米");
item.setImages("http://images.baidu.com/123.jsp");
itemMapper.save(item);
}
7.批量添加
//注入模板
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
//注入mapper
@Autowired
private ItemMapper itemMapper;
/*
* 批量添加数据
* */
@GetMapping("/indexList")
public void indexList(){
List<Item> list = new ArrayList<>();
list.add(new Item(2L, "坚果手机R1", " 手机", "锤子", 3699.00, "http://image.baidu.com/13123.jpg"));
list.add(new Item(3L, "华为META10", " 手机", "华为", 4499.00, "http://image.baidu.com/13123.jpg"));
list.add(new Item(4L, "小米META10", " 手机", "华为", 4499.00, "http://image.baidu.com/13123.jpg"));
list.add(new Item(5L, "三星META10", " 手机", "华为", 4499.00, "http://image.baidu.com/13123.jpg"));
list.add(new Item(6L, "苹果META10", " 手机", "华为", 4499.00, "http://image.baidu.com/13123.jpg"));
// 接收对象集合,实现批量新增
Iterable<Item> items = itemMapper.saveAll(list);
System.out.println("items = " + items);
}
8.修改数据
Elasticsearchr中没有修改,他先删除在新增,修改和新增同一哥接口,区分的就是ID
代码如下
/*
* 修改数据
* */
@GetMapping("update")
public void update(){
Item item = new Item(2L, "雅马哈R1", " 手机", "锤子", 3699.00, "http://image.baidu.com/13123.jpg");
itemMapper.save(item);
}
9.查询
ElasticsearchRepository提供了一些基本的查询方法:
/*
* 查询
* */
@GetMapping("findAll")
public void findAll(){
// 查询所有
Iterable<Item> all = itemMapper.findAll();
Iterator<Item> iterator = all.iterator();
while (iterator.hasNext()){
System.out.println("查询所有数据" + iterator.next());
}
// 分页查找
Page<Item> all1 = itemMapper.findAll(PageRequest.of(1, 3));
System.out.println("获取总条数" + all1.getTotalElements());
for (Item item : all1) {
System.out.println("item = " + item);
}
// 排序
Iterable<Item> price = itemMapper.findAll(Sort.by("price").descending());
Iterator<Item> iterator1 = price.iterator();
while (iterator1.hasNext()){
System.out.println("iterator1.next() = " + iterator1.next());
}
}
10.自定义查询
- matchQuery:词条匹配,先分词然后在调用termQuery进行匹配
- TermQuery:词条匹配,不分词
- wildcardQuery:通配符匹配
- fuzzyQuery:模糊匹配
- rangeQuery:范围匹配
- booleanQuery:布尔查询
1.match query
//自定义查询
@GetMapping("/query")
public void query(){
// 构建查询条件
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
// 添加基本分词查询
queryBuilder.withQuery(QueryBuilders.matchQuery("title","META10"));
// 收索获取结果
Page<Item> search = itemMapper.search(queryBuilder.build());
System.out.println("命中的记录数" + search.getTotalElements());
for (Item item : search) {
System.out.println("item = " + item);
}
NativeSearchQueryBuilder:Spring提供的一个查询条件构建器,帮助构建json格式的 请求体
QueryBuilders.matchQuery(“title”, “小米手机”):利用QueryBuilders来生成一个查 询。
QueryBuilders提供了大量的静态方法,用于生成各种不同类型的查询:
Page:默认是分页查询,因此返回一的是一个分页的结果对象,包含属性:
- totalElements:总条数
- totalPages:总页数
- Iterator:迭代器,本身实现了Iterator接口,因此可直接迭代得到当前页的数据
2.termQuery
@GetMapping("/termQuery")
public void termQuery(){
NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder();
searchQueryBuilder.withQuery(QueryBuilders.termQuery("title", "小米"));
// 默认自动分页 默认查询第一页的10条数据
Page<Item> search = itemMapper.search(searchQueryBuilder.build());
System.out.println("命中多少条" + search.getTotalElements());
for (Item item : search) {
System.out.println("item = " + item);
}
}
3.fuzzyQuery
@GetMapping("/fuzzyQuery")
public void fuzzyQuery(){
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
//模糊匹配
nativeSearchQueryBuilder.withQuery(QueryBuilders.fuzzyQuery("title","小米"));
Page<Item> search = itemMapper.search(nativeSearchQueryBuilder.build());
System.out.println("命中了" + search.getTotalElements());
for (Item item : search) {
System.out.println("item = " + item);
}
booleanQuery
BooleanQuery(组合查询)
与 | 或 | 非 |
---|---|---|
&& | || | ! |
MUST | SHOULD | MUST_NOT |
注意点:
BooleanClause用于表示布尔查询子句关系的类,包括:BooleanClause.Occur.MUST,BooleanClause.Occur.MUST_NOT,BooleanClause.Occur.SHOULD。必须包含,不能包含,可以包含三种.有以下6种组合:
1.MUST和MUST:交集。
2.MUST和MUST_NOT:表示查询结果中不能包含MUST_NOT所对应得查询子句的检索结果。
3.SHOULD与MUST_NOT:连用时,功能同MUST和MUST_NOT。
4.SHOULD与MUST连用时,结果为MUST子句的检索结果,但是SHOULD可影响排序。
5.SHOULD与SHOULD:并集。
6.MUST_NOT和MUST_NOT:无意义,检索无结果。
@GetMapping("/testBooleanQuery")
public void testBooleanQuery(){
NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
builder.withQuery(QueryBuilders.boolQuery().must(QueryBuilders.termQuery("title","手机"))
.must(QueryBuilders.termQuery("brand","小米"))
);
Page<Item> list = itemMapper.search(builder.build());
for(Item item:list){
System.out.println(item);
}
}
@GetMapping("/RangeQuery")
public void RangeQuery(){
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
// queryBuilder.withQuery(QueryBuilders.fuzzyQuery("title","小目"));
queryBuilder.withQuery(QueryBuilders.rangeQuery("price").from(3000).to(6000));
Page<Item> page = itemMapper.search(queryBuilder.build());
for(Item it:page){
System.out.println(it);
}
}
@GetMapping("/Sort")
public void Sort(){
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
//添加查询条件
nativeSearchQueryBuilder.withQuery(QueryBuilders.termQuery("title","小米"));
nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort("id").order(SortOrder.DESC));
Page<Item> search = itemMapper.search(nativeSearchQueryBuilder.build());
System.out.println("命中数据" + search.getTotalElements()+"条");
for (Item item : search) {
System.out.println("item = " + item);
}
}