简介
基本概念
常用术语
详细说明
字段类型
注意事项
ES windows 版 安装部署
ElasticSearch-head 安装部署
IK分词器安装
使用Postman创建索引
创建一个空的索引 testindex (非结构化索引)
对索引的mappings进行赋值,并转换为结构化索引
SpringBoot 集成实战
https://blog.csdn.net/heiyogl/article/details/103281714
Elasticsearch也是基于Lucene的全文检索库,本质也是存储数据,很多概念与MySQL类似的。
对比关系:
索引库(indices) |
Databases 数据库 |
类型(type) |
Table 数据表 |
文档(Document) |
Row 行 |
字段(Field) |
Columns 列 |
1.1:文档Document:用户存储在Elasticsearch中的文档;
1.2:索引 Index:由具有相同字段的文档列表组成;
1.3:节点Node:一个Elasticsearch的运行实例,是集群的构成单元;
1.4:集群Cluster:由一个或多个节点组成,对外提供服务;
1.5:分片:每个索引都有多个分片,每个分片是一个Lucene索引;
1.6:备份:拷贝一份分片就完成了分片的备份;
在Elasticsearch有一些集群相关的概念:
1、Elasticsearch本身就是分布式的,因此即便你只有一个节点,Elasticsearch默认也会对你的数据进行分片和副本操作;当你向集群添加新数据时,数据也会在新加入的节点中进行平衡;
2、ES创建索引时默认创建5个分片一个备份 , 分片的数量只能在创建索引时指定,备份可以动态修改;
3、索引命名规范:字母小写,且不含中划线。
下载地址: https://www.elastic.co/cn/downloads/elasticsearch
文件名: elasticsearch-7.4.0-windows-x86_64.zip
Es 安装包内本身内置了JDK,且内置的JDK版本是该Es所推荐使用的版本。
1、将文件 elasticsearch-7.4.0-windows-x86_64.zip 解压到安装目录下;
2、配置es使用内置的jdk(而非电脑所配置的JAVA_HOME环境变量)
使用文本编辑器编辑 bin/elasticsearch-env.bat 直接添加了JAVA_HOME 的配置,具体如下:
rem 配置自己的jdk
set JAVA_HOME=E:/xxx/elastic/elasticsearch-7.4.0/jdk
3、双击打开解压后 bin 目录下的 elasticsearch.bat
浏览器打开地址: http://127.0.0.1:9200/ 看到如下界面说明启动好了
ElasticSearch-head 是一个用来查看ES的运行状态和数据的可视化工具,ElasticSearch-head依赖 node.js
1、node.js 安装
下载地址: http://nodejs.cn/download/
文件名: node-v12.13.0-x64.msi
双击打开即可进入安装环节,安装完成后,打开cmd 命令,输入 node --version 命令即可查看安装的版本。
node.js 安装完成后,切换到 node.js 的安装目录(cmd中输入 npm config ls 命令可查看安装目录),运行命令安装 grunt,命令如下: npm install -g grunt-cli
2、ElasticSearch-head 安装
下载地址: https://github.com/mobz/elasticsearch-head
文件名: elasticsearch-head-master.zip
下载完成后,cmd 进入 elasticsearch-head-master 的解压目录,然后执行 npm install 命令(对改目录下的相关文件解压并安装)。安装完成后,输入启动命令 npm run start
浏览器地址输入: http://127.0.0.1:9100/ 可查看 head 界面
Es默认不允许跨域链接,所以默认会显示未连接的状态。
在es > config 目录下,打开 elasticsearch.yml 文件,并在末尾处添加配置:
http.cors.enabled: true
http.cors.allow-origin: "*"
保存,重启es,且刷新elasticsearch-head 即可链接。
下载地址: https://github.com/medcl/elasticsearch-analysis-ik
文件名: elasticsearch-analysis-ik-master.zip
安装步骤:
1、cmd 进入 elasticsearch-analysis-ik-master 解压目录;
2、执行 mvn clean package 命令进行打包,打包完后会多出一个 target 文件夹。打包zip文件路径为: target > releases > elasticsearch-analysis-ik-7.4.0.zip ;
3、在es安装目录下的 plugins 文件夹下创建 analysis-ik 文件夹,并将上一步打包好的 elasticsearch-analysis-ik-7.4.0.zip 解压到此处,如下图:
4、重启 ES,可以启动,则说明安装成功。
http://127.0.0.1:9200/testindex
通过 elasticsearch-head 可以看到该索引的mappings 是空的(非结构化索引)
mapping类似于数据库表的结构,主要用于
1.定义index下的字段名;
2.定义字段类型;
3.定义倒排索引相关的配置。
http://127.0.0.1:9200/testindex/_mapping
{"properties":{"name":{"type":"text"},"sex":{"type":"integer"}}}
通过 elasticsearch-head 可以看到该索引的mappings
基于SpringBoot实现新增/修改、删除、查询、聚合统计的功能
1、pom.xml 添加依赖
org.elasticsearch
elasticsearch
7.2.0
org.elasticsearch.client
elasticsearch-rest-high-level-client
7.2.0
2、application.properties 配置ES地址
elasticsearch.ip=127.0.0.1:9200
3、创建 ElasticsearchRestClient.java
@Configuration
public class ElasticsearchRestClient {
private static final int ADDRESS_LENGTH = 2;
private static final String HTTP_SCHEME = "http";
private static final String ARTICLE_INDEX_NAME = "article_index";
@Value("${elasticsearch.ip}")
String[] ipAddress;
private RestHighLevelClient highLevelClient;
@Bean
public RestClientBuilder restClientBuilder() {
HttpHost[] hosts = Arrays.stream(ipAddress)
.map(this::makeHttpHost)
.filter(Objects::nonNull)
.toArray(HttpHost[]::new);
return RestClient.builder(hosts);
}
@Bean(name = "highLevelClient")
public RestHighLevelClient highLevelClient(@Autowired RestClientBuilder restClientBuilder) {
highLevelClient = new RestHighLevelClient(restClientBuilder);
return highLevelClient;
}
private HttpHost makeHttpHost(String s) {
assert StringUtils.isNotEmpty(s);
String[] address = s.split(":");
if (address.length == ADDRESS_LENGTH) {
String ip = address[0];
int port = Integer.parseInt(address[1]);
return new HttpHost(ip, port, HTTP_SCHEME);
} else {
return null;
}
}
// 新增 或 修改文档(若ID存在,则修改)
public void insertOrUpdateArticle(EsArticle article) throws IllegalArgumentException, IllegalAccessException{
try {
XContentBuilder builder = XContentFactory.jsonBuilder();
builder.startObject();
// 遍历实体类
Class clas = article.getClass();
Field[] fields = clas.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
Field f = fields[i];
f.setAccessible(true);
// es字段赋值
if (f.getType().toString().equals("class java.sql.Timestamp")) { //若字段类型为时间类型,则将其转换为 long 进行存储
builder.field(f.getName(), ((Timestamp)f.get(article)).getTime());
} else {
builder.field(f.getName(), f.get(article));
}
}
builder.endObject();
IndexRequest request = new IndexRequest(ARTICLE_INDEX_NAME).source(builder);
request.id(article.getId()); // 通过指定 id 来实现:若存在则更新记录,否则插入记录
highLevelClient.index(request, RequestOptions.DEFAULT);
} catch (IOException e) {
e.printStackTrace();
}
}
// 批量新增 或 修改文档(若ID存在,则修改)
public int insertOrUpdateBatchArticle(List list) {
int result = -1;
try {
BulkRequest request = new BulkRequest();
for (EsArticle article : list) {
XContentBuilder builder = XContentFactory.jsonBuilder();
builder.startObject();
// 遍历实体类
Class clas = article.getClass();
Field[] fields = clas.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
Field f = fields[i];
f.setAccessible(true);
// es字段赋值
if (f.getType().toString().equals("class java.sql.Timestamp")) { //若字段类型为时间类型,则将其转换为 long 进行存储
if (null == f.get(article)) {
builder.field(f.getName(), 0l);
} else {
builder.field(f.getName(), ((Timestamp)f.get(article)).getTime());
}
} else {
builder.field(f.getName(), f.get(article));
}
}
builder.endObject();
IndexRequest requestItem = new IndexRequest(ARTICLE_INDEX_NAME).source(builder);
requestItem.id(article.getId()); // 通过指定 id 来实现:若存在则更新记录,否则插入记录
request.add(requestItem);
}
highLevelClient.bulk(request, RequestOptions.DEFAULT);
result = list.size();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
// 批量删除
public void deleteBatchArticle(Collection idList) {
BulkRequest request = new BulkRequest();
idList.forEach(item -> request.add(new DeleteRequest(ARTICLE_INDEX_NAME, item.toString())));
try {
highLevelClient.bulk(request, RequestOptions.DEFAULT);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 通过查询条件实现分页查询
* @param queryParam 查询条件(Map)
* @param pageIndex 分页索引,从第 1 页开始
* @param pageSize 每页条数
* @param order 排序数组,[排序字段][排序方式(asc | desc)]
*/
public void queryArticle(Map queryParam, int pageIndex, int pageSize, String[][] order) {
List
4、调用测试
// 新增记录
public void create() {
EsArticle article = new EsArticle();
article.setTid("tidv");
article.setTitle("标题");
try {
client.insertOrUpdateArticle(article);
} catch (IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
}
System.out.println("success ..");
}
// 查询
public void query() {
Map queryParam = new HashMap();
queryParam.put("content", "深圳创业板");
client.queryArticle(queryParam, 1, 5, null);
System.out.println("success..");
}
// 分组统计
public void count() {
Map queryParam = new HashMap();
String[][] order = {{"tid", "desc"}};
LinkedHashMap resultMap = client.countArticle(queryParam, 1, 5, order, "by_tid", "tid");
int row = 1;
for (Entry entry : resultMap.entrySet()) {
System.out.println(row++ + " > " + entry.getKey() + ":" + entry.getValue());
}
System.out.println("success..");
}
// 多字段分组统计
public void countArticleMultiple() {
String[][] order = {{"media_type", "desc"}};
Map queryParam = new HashMap();
queryParam.put("content", "深圳创业板");
client.countArticleMultiple(queryParam, 1, 5, order, "tid", "media_type");
System.out.println("success..");
}
至此,就完成了从安装部署到集成常用功能的实战工作。
参考文献:
https://blog.csdn.net/u014082714/article/details/89963046
https://blog.csdn.net/chen_2890/article/details/83895646
https://blog.csdn.net/weixin_37703281/article/details/90974279
https://www.jianshu.com/p/1fbfde2aefa5