赞
踩
Elaticsearch,简称为ES,ES是一个开源的高扩展的分布式全文检索引擎,它可以近乎实时的存储、检索数据;本身扩展性很好,可以扩展到上百台服务器,处理 PB 级别(大数据时代)的数据。ES由 Java 语言开发并使用 Lucene 作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的 RESTFULL API 来隐藏 Lucene 的复杂性,从而让全文搜索变得简单。Logstash 负责数据的采集,处理(丰富数据,数据转型等),Kibana 负责数据展,分析及管理。Elasticsearch 处于最核心的位置,它可以帮我们对数据进行快速地搜索及分析。
1.查询要安装jdk的版本:
命令: yum -y list java*
2.安装jdk1.8
命令:yum install -y java-1.8.0-openjdk.x86_64
3.查询jdk版本
命令: java -version
这样就安装成功了。默认给安装到usr/lib/jvm/ 还有一种手动的
Linux版本
下载地址: [https://www.elastic.co/cn/downloads/past-releases/elasticsearch-7-6-1]: https://www.elastic.co/cn/downloads/past-releases/elasticsearch-7-6-1
Xftp Xshell 个人免费申请
https://www.netsarang.com/zh/free-for-home-school/
通过 XFTP 这个上传到服务器或者虚拟机指定文件夹位置:
位置:/usr/local/src/software
XShell 工具连接到服务器或者虚拟机
tar -zxvf elasticsearch-7.6.1-linux-x86_64.tar.gz
改文件夹名称,方便:mv elasticsearch-7.6.1 elaticSeach7
ES 本身相当一个数据库
elasticsearch7 文件夹创建 data
文件夹,用于存放数据:mdkir data
进入 data
文件夹给于文件夹权限,执行 pwd
data /usr/local/src/software/elaticseach7/data
bin: ES启动文件 elasticsearch.bat / elasticsearch
config:配置目录
data:数据目录
jdk,lib:java运行环境以及依懒包
logs:日志目录
modules,plugins:模块及插件目录,head插件可以存放在plugins目录下
修改配置文件elasticseach.yml
,进入 elasticseach7
的 confing
文件夹,编辑 elasticseach.yml 文件夹: vim elasticseach.yml
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2k8mxaTy-1615343315058)(C:\Users\heng\AppData\Roaming\Typora\typora-user-images\image-20210308110744983.png)]
修改完成 按 :wq
保存退出,回到elasticsearch7 文件夹, 进入 logs 文件夹, pwd
查看文件夹路径,复制
重新回到 config 目录编辑 elasticsearch.yml 文件:
cd /usr/local/src/software/elasticsearch7/config
vim elasticsearch.yml
在config目录下的elasticsearch.yml文件末尾添加跨域允许
# 跨域问题
http.cors.enabled: true
http.cors.allow-origin: "*"
http.cors.allow-headers: Authorization,X-Requested-with,Content-Length,Content-Type
配置流程参考:https://blog.csdn.net/weixin_43019282/article/details/105352982
ES 默认自带有分词器,只支持英文分词,需要安装中文分词插件
IK 分词器 Github 地址:https://github.com/medcl/elasticsearch-analysis-ik
下载 等应版本:https://github.com/medcl/elasticsearch-analysis-ik/releases/tag/v7.6.1
使用 Xshell 上传 原来的位置
plugins
文件夹, 新建一个 ik
文件夹,用于存放 IK
分词器插件:没有这个指令 先下载 unzip 命令 :yum install unzip zip
重新执行 :unzip elasticsearch-analysis-ik-7.6.1.zip -d /usr/local/src/software/elasticsearch7/plugins/ik
- 进入 ik 目录下的 config 目录:
- cd /usr/local/src/software/elasticsearch7/plugins/ik/config
- 查看:ll
如果出现一些网络热词,我们想对其继续分词配置,我们需要到 ik 文件夹中 config 文件夹中的IKAnalyzer.cfg.xml
去配置: vim IKAnalyzer.cfg.xml
如果需要加一些额外的网络新词,可以把这些词放到 自己新建的 ext_dict 文件中,每个词直接都要换行,就像extra_main.doc文件的格式一样就行
- 进入 bin 目录: cd /usr/local/src/software/elasticsearch7/bin 再执行命令:./elasticsearch
- 运行ES服务! 后台运行命令:
./elasticsearch -d
- 关闭ES 服务: ps -ef|grep elastic
- 查看进程,
- ps -elf
- 并使用 kill -9 进程id 来结束进程
入坑一:
不能以 root 用户去启动 ES 服务
解决方案
adduser elasticsearch
su elasticsearch
命令,重新回到 bin 目录执行 ES 服务‘入坑二:
解决方案
在 elasticsearch 的 config 目录下,修改 elasticsearch.yml 配置文件
入坑三:
ERROR: [1] bootstrap checks failed
[1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
解决方案
- 修改配置sysctl.conf
- vim /etc/sysctl.conf
- 在最后一行添加下面配置:
- vm.max_map_count=655360
- 保存退出并执行命令:
- sysctl -p
重新启动 elasticsearch 服务
访问成功:
还有个 坑 服务器1核2G的 内存小 不能运行 需要修改
看 海贼王的 原章修改 :Linux环境下ElasticSearch的安装与使用
Relational DB | Elasticsearch |
---|---|
数据库(database) | 索引(indices) |
表(tables) | 类型(types) |
行(一条记录)(rows) | 文档(documents) |
字段(columns) | 属性(fields) |
Elasticsearch 是一个接近实时的搜索平台,从索引一个文档直到这个文档被搜索到有一个轻微的延迟(通知1秒内)
一个索引就是一个拥有几分相类似特征的文档的集合。比如说,你可以有一个客户数据索引,另一个产品目录的索引,还有一个订单数据的索引。一个索引由一个名字标识(必须全部是小写字母的),并且当我们要对这个索引中的文档进行索引、搜索、更新和删除的时候,都要使用到这个名字。索引类似关系型数据库Database的概念。在一个集群中,如果你想,可以定义任意多的索引。
在一个索引中,你可以定义一种或多种类型。一个类型是你的索引的一个逻辑的分类/分区,其语义完全由你来定。通常,会为具有一组共同字段的文档定义一个类型。假设你运营一个博客平台并且将你所有的数据存储到一个索引中。在这个索引中,你可以为用户数据定义一个类型,为博客数据定义另一个类型还有评论数据也可以定义另一个类型。类型类似于关系型数据库中Table的概念
NOTE:在5.X版本以前可以在一个索引中定义多个类型,6.X之后版本也可以使用,不推荐,在7~8.X版本中彻底移除一个索引中创建多个类型
Mapping是ES中的一个很重要的内容,它类似于传统关系型数据中table的schema,用于定义一个索引(index)中的类型(type)的数据的结构
在ES中,我们可以手动创建type(相当于table)和mapping(相关与schema),也可以采用默认创建方式。在默认配置下,ES可以根据插入的数据自动创建type及其mapping. mapping中主要包括字段名、字段数据类型和字段索引类型
一个文档是一个可被索引的基础信息单元,类似于表中的一条记录。比如,你可以拥有某一个员工的文档,也可以拥有某个商品的一个文档
文档以采用了轻量级的数据交换格式JSON来表示
使用命令行的方式 curl 发送请求:
查看ES服务健康状态:
curl -X GET "ip地址:9200/_cat/health?v"
查看ES服务中的节点:
curl -X GET "ip地址:9200/_cat/indices?v"
查看ES服务中的所有索引:
curl -X PUT “ip地址:9200/myindex”
curl -X GET “ip地址:9200/_cat/indices?v”
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SfO5SxBy-1615343315067)(C:\Users\heng\AppData\Roaming\Typora\typora-user-images\image-20210309095222486.png)]
curl -X DELETE “ip地址:9200/myindex”
使用服务器 curl
手动输入请求 ES
服务不方便,所有使用Postman 请求方法
PUT IP地址:9200/myindex/_doc/1
GET IP地址:9200/myindex/_doc/1
PUT IP地址:9200/myindex/_doc/1
DELETE IP地址:9200/myindex/_doc/1
ES 添加些数据
PUT IP 地址:9200/myindex/_doc/1 { "title":"海贼王", "content":"船长是路飞,副船长是索隆~" } PUT IP 地址:9200/myindex/_doc/2 { "title":"火影忍者", "content":"七代火影是鸣人,八代火影是木叶丸~" } PUT IP 地址:9200/myindex/_doc/3 { "title":"一拳超人", "content":"主角是埼玉,配角是杰诺斯~" } PUT IP 地址:9200/myindex/_doc/4 { "title":"进击的巨人", "content":"人类最牛的是兵长,巨人最菜的是男主~" } PUT IP 地址:9200/myindex/_doc/5 { "title":"名侦探柯南", "content":"男主是柯南,女主不确定~" } PUT IP 地址:9200/myindex/_doc/6 { "title":"海贼王路飞", "content":"路飞是要成为海贼我的男人~" } PUT IP 地址:9200/myindex/_doc/7 { "title":"路飞的果实能力", "content":"路飞是吃了橡胶果实的男人~" }
GET IP地址:9200/myindex/_search
结果:
{ "took": 100, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 7, "relation": "eq" }, "max_score": 1.0, "hits": [ { "_index": "myindex", "_type": "_doc", "_id": "2", "_score": 1.0, "_source": { "title": "火影忍者", "content": "七代火影是鸣人,八代火影是木叶丸~" } }, { "_index": "myindex", "_type": "_doc", "_id": "3", "_score": 1.0, "_source": { "title": "一拳超人", "content": "主角是埼玉,配角是杰诺斯~" } }, { "_index": "myindex", "_type": "_doc", "_id": "4", "_score": 1.0, "_source": { "title": "进击的巨人", "content": "人类最牛的是兵长,巨人最菜的是男主~" } }, { "_index": "myindex", "_type": "_doc", "_id": "5", "_score": 1.0, "_source": { "title": "名侦探柯南", "content": "男主是柯南,女主不确定~" } }, { "_index": "myindex", "_type": "_doc", "_id": "6", "_score": 1.0, "_source": { "title": "海贼王路飞", "content": "路飞是要成为海贼我的男人~" } }, { "_index": "myindex", "_type": "_doc", "_id": "7", "_score": 1.0, "_source": { "title": "路飞的果实能力", "content": "路飞是吃了橡胶果实的男人~" } }, { "_index": "myindex", "_type": "_doc", "_id": "8", "_score": 1.0, "_source": { "title": "海贼王", "content": "船长是路飞,副船长是索隆~" } } ] } }
GET IP地址/myindex/_search?q=title:海贼王
或者
GET IP地址/myindex/_search?q=content:路飞
结果:
{ "took": 3, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 3, "relation": "eq" }, "max_score": 1.9062529, "hits": [ { "_index": "myindex", "_type": "_doc", "_id": "8", "_score": 1.9062529, "_source": { "title": "海贼王", "content": "船长是路飞,副船长是索隆~" } }, { "_index": "myindex", "_type": "_doc", "_id": "6", "_score": 1.8387749, "_source": { "title": "海贼王路飞", "content": "路飞是要成为海贼我的男人~" } }, { "_index": "myindex", "_type": "_doc", "_id": "7", "_score": 1.8387749, "_source": { "title": "路飞的果实能力", "content": "路飞是吃了橡胶果实的男人~" } } ] } }
GET IP地址:9200/myindex/_search
{
"query":{
//多个匹配
"multi_match":{
//查询条件 路飞
"query":"路飞",
// 从title 和 content 字段中匹配是否存在 路飞 数据
"fields":["title","content"]
}
}
}
结果:
{ "took": 6, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 3, "relation": "eq" }, "max_score": 2.2700202, "hits": [ { "_index": "myindex", "_type": "_doc", "_id": "6", "_score": 2.2700202, "_source": { "title": "海贼王路飞", "content": "路飞是要成为海贼我的男人~" } }, { "_index": "myindex", "_type": "_doc", "_id": "7", "_score": 1.9412584, "_source": { "title": "路飞的果实能力", "content": "路飞是吃了橡胶果实的男人~" } }, { "_index": "myindex", "_type": "_doc", "_id": "8", "_score": 1.9062529, "_source": { "title": "海贼王", "content": "船长是路飞,副船长是索隆~" } } ] } }
<!--elasticsearch 可以中文搜索-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
application.yml 中配置
spring:
thymeleaf:
mode: HTML
profiles:
active: dev
messages:
basename: i18n/messages
# elasticsearch 配置
rest:
# ip是服务器ip地址
uris: http://8.xxx.xxx.xxx:9200
# 账号 有账号密码 就配置 没有不需要
username: root
# 密码
password: @@7750731hua
ES 几个常用注解
- @Document: 声明索引库配置
- indexName:索引库名称
- type:映射类型。如果未设置,则使用小写的类简单名称(版本4.0以上 不推荐使用)
- shards: 分片数量,默认 5
- replicas: 副本数量, 默认 1
- @id:声明实体类的id
- @Field:声明字段属性
- type: 字段的数据类型
- analyzer: 指定在存储时候使用的分词类型
- searchAnalyzer:指定在搜索时候使用的分词器类型
- index: 是否创建索引
推荐观看海贼王文章
Spring Data 形式:SpringBoot 操作ES增删改
RestHighLevelClient 形式:SpringBoot整合ES7.6的API(RestHighLevelClient)
- 三种形式 (API使用)
- 主 RestHighLevelClient 客户端使用 加依赖就 可 使用
- 副 SpringData 也 就是 jpa形式 使用ElasticsearchRepository 调用API
- 副 Jest 也是 调用API 2018年已 停止更新 (不推荐使用)
Maven:
<!--elasticsearch 可以中文搜索--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-elasticsearch</artifactId> <version>2.2.5.RELEASE</version> </dependency> <!--json--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.32</version> </dependency> <!--lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.10</version> </dependency>
实体类:
@Data
public class DiscussPost {
private int id;
private String blogName;
private String goods;
public DiscussPost(int id, String blogName, String goods) {
this.id = id;
this.blogName = blogName;
this.goods = goods;
}
}
测试类:
/** * @Description: ex7.6.x客户端测试 API */ @SpringBootTest public class ElasticsearchTest { @Autowired @Qualifier("restHighLevelClient") private RestHighLevelClient client; /** * 索引创建 Request:PUT xin_index */ @Test void testCreateIndex() throws IOException { // 1.创建索引请求 CreateIndexRequest request = new CreateIndexRequest("xin_index"); // 2.执行创建请求 IndicesClient 请求后获得响应 CreateIndexResponse createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT); //输出结果 System.out.println(createIndexResponse); } /** * 获取索引 GET */ @Test void testExisIndex() throws IOException { // 1.获取索引库的请求 GetIndexRequest request = new GetIndexRequest("xin_index"); // 2.执行获取索引库的请求 boolean exists = client.indices().exists(request, RequestOptions.DEFAULT); System.out.println(exists);// 索引库存在 输出 true 否则 false } /** * 删除索引 DELETE */ @Test void testDeleteIndex() throws IOException { // 1.删除索引库的请求 DeleteIndexRequest request = new DeleteIndexRequest("xin_index"); // 2.执行删除索引库的请求 AcknowledgedResponse delete = client.indices().delete(request, RequestOptions.DEFAULT); // 输出结果 System.out.println(delete.isAcknowledged());// 删除成功输出true,否则为false } /** * 添加文档 */ @Test void testAddDocument() throws IOException { // 1.创建对象 DiscussPost user = new DiscussPost(4,"恒新","书"); // user.setId(1); // user.setBlogName("恒新"); // user.setGoods("书"); // 2.创建请求 IndexRequest request = new IndexRequest("xin_index"); // 3.构建请求规则:PUT /csp_index/_doc/1 request.id("4"); request.timeout(TimeValue.timeValueSeconds(1)); //request.timeout("1s"); // 4.将user对象数据放入请求,json 数据: 需要用到fastjson request.source(JSON.toJSONString(user), XContentType.JSON); // 导下json依赖就用下面的 //request.source(JSON.toJSONString(user), XContentType.JSON); // 5.客户端发送请求,获取响应的结果 IndexResponse indexResponse = client.index(request, RequestOptions.DEFAULT); // 输出结果 // IndexResponse[index=csp_index,type=_doc,id=1,version=1,result=created,seqNo=0,primaryTerm=1,shards={"total":2,"successful":1,"failed":0}] System.out.println(indexResponse.toString()); System.out.println(indexResponse.status());// CREATED:表示创建成功 } /** * 获取文档,判断是否存在 */ @Test void testIsExists() throws IOException { // 1.获取文档信息请求 GetRequest getRequest = new GetRequest("xin_index","1"); // 2.执行获取文档信息的请求 GetResponse getResponse = client.get(getRequest, RequestOptions.DEFAULT); System.out.println(getResponse.getSourceAsString());// {"DiscussPost{id=1, blogName='恒新', goods='书'}":"JSON"} System.out.println(getResponse); //{"_index":"xin_index","_type":"_doc","_id":"1","_version":1,"_seq_no":0,"_primary_term":1,"found":true,"_source":{"DiscussPost{id=1, blogName='恒新', goods='书'}":"JSON"}} } /** * 更新文档信息 */ @Test void testUpdateDocument() throws IOException { // 1.更新文档请求 UpdateRequest updateRequest = new UpdateRequest("xin_index", "1"); // 设置请求超时时间 updateRequest.timeout("1s"); // user数据对象封装到json中 DiscussPost user = new DiscussPost(3,"恒久","羽毛球"); // user.setBlogName("恒久"); // user.setGoods("羽毛球"); updateRequest.doc(JSON.toJSONString(user), XContentType.JSON); // 2.执行更新文档请求 UpdateResponse updateResponse = client.update(updateRequest, RequestOptions.DEFAULT); // 输出结果 System.out.println(updateResponse.status());// OK:表示更新成功 } /** * 删除文档记录 */ @Test void testDeleteDocument() throws IOException { // 1.删除文档请求 DeleteRequest deleteRequest = new DeleteRequest("xin_index", "1"); deleteRequest.timeout("1s"); // 2.执行删除文档请求 DeleteResponse deleteResponse = client.delete(deleteRequest, RequestOptions.DEFAULT); // 输出结果 System.out.println(deleteResponse.status());// OK:表示删除成功 } /** * 批量插入数据 */ @Test void testBulkRequest() throws IOException{ // 1.批处理请求 BulkRequest bulkRequest = new BulkRequest(); bulkRequest.timeout("10s"); // user 数据集合 ArrayList<DiscussPost> list = new ArrayList<>(); //DiscussPost user = new DiscussPost(); //DiscussPost user = new DiscussPost(); list.add(new DiscussPost(0,"路飞","恶魔果实")); list.add(new DiscussPost(1,"索隆","剑术")); list.add(new DiscussPost(2,"山治","厨师")); System.out.println(list); for (int i = 0; i < list.size(); i++) { // 批量更新,修改,删除 都是在此进行操作 bulkRequest.add( new IndexRequest("xin_index") // 批量赋值文档id: 如果不在自己赋值文档id,会默认生成随机的文档id .id("" + (i + 1)) // ArrayList转换成json .source(JSON.toJSONString(list.get(i)), XContentType.JSON) ); } // 2.执行批量插入请求 BulkResponse bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT); // 输出结果 System.out.println(bulkResponse.status());// OK: 表示批量插入成功! } /** * ES中数据搜索 * SearchRequest 搜索请求 * SearchSourceBuilder 条件构造 * HighlightBuilder 构建高亮 * TermQueryBuilder 精确查询 * XXXQueryBuilder 构建我们需要用到的命令 */ @Test void testSearch() throws IOException { // 1.创建搜索请求 SearchRequest searchRequest = new SearchRequest("xin_index"); // 2.构建搜索条件:条件构造器 SearchSourceBuilder SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); //高亮结果的条件构造器 HighlightBuilder highlightBuilder = new HighlightBuilder(); highlightBuilder.field("blogName");// 要高亮的字段 highlightBuilder.requireFieldMatch(false);//不需要多个字段高亮,如果需要设置true highlightBuilder.preTags("<span style='color:blue'>"); highlightBuilder.postTags("</span>"); // 条件构造器,开启搜索结果高亮,并加入高亮结果的条件构造器 sourceBuilder.highlighter(highlightBuilder); /** * 查询条件,使用QueryBuilders工具类 * QueryBuilders.termQuery() 精确查询 * QueryBuilders.matchAllQuery() 匹配所有 */ //TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name", "xin");// 精确查询 //MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();// 搜索所有数据 MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("blogName", "索隆");// 搜索字段name为路飞的数据 //查询条件(matchQueryBuilder)放入条件构造器 sourceBuilder.query(matchQueryBuilder); // 条件构造器,开启分页条件: 从第1个数据开始,每页展示5条结果数据 sourceBuilder.from(0); sourceBuilder.size(5); // 条件构造器,搜索请求超时时间60s sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS)); // 将条件构造器放入搜索请求 searchRequest.source(sourceBuilder); // 执行搜索请求,并获得searchResponse响应 SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT); // 搜索得到的所有结果都封装在hits里面,拿数据从hits里面获取 SearchHits hits = searchResponse.getHits(); // System.out.println("-------"); // System.out.println(JSON.toJSONString(hits)); // System.out.println("-------"); // 遍历hits:解析结果,并将结果放入resultList集合 ArrayList<Map<String, Object>> resultList = new ArrayList<>(); for (SearchHit documentFields : searchResponse.getHits()) { // 获取高亮的字段 Map<String, HighlightField> highlightFields = documentFields.getHighlightFields(); HighlightField name = highlightFields.get("blogName");// 获取高亮的字段 Map<String, Object> sourceAsMap = documentFields.getSourceAsMap();// 先获取原来未高亮的结果 // 解析高亮的字段, 将原来未高亮的title字段换成高亮的字段 if (name != null) { Text[] fragments = name.fragments(); String newName = ""; for (Text text : fragments) { newName += text; } // 高亮字段替换原来内容 sourceAsMap.put("blogName", newName); } resultList.add(documentFields.getSourceAsMap()); } // 遍历resultList resultList.forEach(item -> { System.out.println(item);// {name=<span style='color:red'>路</span><span style='color:red'>飞</span>, age=1} }); } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。