ElasticSearch—搜索引擎

本文详细介绍了ElasticSearch的安装过程,包括Linux下的安装、Kibana配置、IK分词器安装及自定义词库配置。同时,文章讲解了ElasticSearch的逻辑结构、基本操作,并阐述了如何在SpringBoot项目中整合ElasticSearch。
摘要由CSDN通过智能技术生成

一、ElasticSearch简介

1.1 ElasticSearch vs Lucene的关系

ElasticSearch vs Lucene的关系,简单⼀句话就是,成品与半成品的关系。
(1)Lucene专注于搜索底层的建设,而ElasticSearch专注于企业应用。
(2)Lucene是单节点的API,ElasticSearch是分布式的—为集群而⽣。
(3)Lucene需要⼆次开发,才能使用。不能像百度或谷歌⼀样,它只是提供⼀个接⼝需要被实现才能使用, ElasticSearch直接拿来用。

1.2 ElasticSearch特性

安装管理便便
大规模分布式
多租户支持
高可用性
操作持久化
友好的RESTful API

二、ElasticSearch逻辑结构

集群–>index(索引)–>types(类型)–>document(文档)–>field(字段)

//index3 索引名,_doc 类型(默认为_doc),102 文档id名, "book_id" 字段名
POST index3/_doc/102
{
 "book_id":102,
 "book_name":"C++程序设计",
 "book_author":"谭浩强",
 "book_price":22.22,
 "book_desc":"C++程序设计中的名著" 
 }
  • 索引(index)
    索引是ElasticSearch存放数据的地方,可以理解为关系型数据库中的⼀个数据库
    索引的名字必须是全部⼩写,不能以下划线开头,不能包含逗号
  • 类型(type)
    类型用于区分同⼀个索引下不同的数据类型,相当于关系型数据库中的表。
    es 6.0 开始不推荐⼀个index下多个type的模式,并且会在 7.0 中完全移除。在7.0 的index下是⽆法创建多个 type
  • 文档(documents)
    文档是ElasticSearch中存储的实体,类比关系型数据库,每个⽂档相当于数据库表中的⼀行数据。
    索引的名字必须是全部⼩写,不能以下划线开头,不能包含逗号
  • 字段(fields)
    ⽂档由字段组成,相当于关系数据库中列的属性,不同的是ES的不同文档可以具有不同的字段集合。
  • 节点与集群
    ⼀个集群是由⼀个或多个节点组成的集合,集群上的节点都具备存储数据,并提供跨节点的索引和搜索功能。
    集群通过⼀个唯⼀的名称作为标识,节点通过设置集群名称就可以加⼊相应的集群,当然这需要节点所在的网络能够发现集群。所以要注意在同⼀个网络中,不同环境、服务的集群的名称不能重复。

三、ElasticSearch安装(Linux)

3.1 Elastic 和 Elasticsearch

Elastic官⽹:https://www.elastic.co/cn/
Elasticsearch官⽹:https://www.elastic.co/cn/products/elasticsearch
Elastic有⼀条完整的产品线及解决方案:Elasticsearch、Logstash、Kibana等,这三个就是大家常说的ELK技术栈。
在这里插入图片描述

3.2 Linux下安装ES

出于安全考虑,elasticsearch默认不允许以root账号运⾏

  • 创建用户设置密码
[root@localhost ~]# useradd es
[root@localhost ~]# passwd es
Changing password for user es.
New password: 
Retype new password:
[root@localhost ~]# chmod 777 /usr/local 【授予es⽤户/usr/local⽬录 可读可写可执⾏权限】
[root@localhost ~]# su - es
[es@localhost ~]$
  • 检查JDK版本(需要JDK1.8+)
[es@localhost ~]# java -version
openjdk version "1.8.0_222-ea"
OpenJDK Runtime Environment (build 1.8.0_222-ea-b03)
OpenJDK 64-Bit Server VM (build 25.222-b03, mixed mode)
  • 将ES的压缩包上传⾄ /usr/local 目录并解压
[es@localhost local]$ tar -zxvf elasticsearch-7.6.1-linux-x86_64.tar.gz
  • 进入elasticsearch-7.6.1中添加data 文件
[es@localhost local]# cd elasticsearch-7.6.1
[es@theo elasticsearch-7.6.1]#mkdir data
[es@theo elasticsearch-7.6.1]# ls
bin config data jdk lib LICENSE.txt log smodules NOTICE.txt plugins README.asciidoc
  • 查看配置文件
[es@theo elasticsearch-7.6.1]# cd config
[es@localhost config]# ls
elasticsearch.yml jvm.options  data log4j2.properties role_mapping.yml roles.yml users
users_roles
  • 修改 jvm.options(修改ElasticSearch占用的内存)
    Elasticsearch基于Lucene的,而Lucene底层是java实现,因此我们需要配置jvm参数
[es@localhost config]# vim jvm.options
# 默认配置如下
# Xms represents the initial size of total heap space
# Xmx represents the maximum size of total heap space
-Xms1g
-Xmx1g
#修改成
-Xms256m
-Xmx256m
  • 修改 elasticsearch.yml
  • 下面是做的单机安装的修改,如果要做集群,只需要在这个配置⽂件中添加其它节点信息即可。
# (修改集群节点信息)(当前是单节点配置)
# ---------------------------------- Cluster -----------------------------------17
cluster.name: my-application
# ------------------------------------ Node ------------------------------------23
node.name: node-1
# --------------------------------- Discovery ----------------------------------72
cluster.initial_master_nodes: ["node-1"]

# (修改数据⽂件和⽇志⽂件存储⽬录路径)
# ---------------------------- Paths ------------------------------
path.data: /usr/local/elasticsearch-7.6.1/data
path.logs: /usr/local/elasticsearch-7.6.1/logs

# (修改绑定的ip,默认只允许本机访问,修改为0.0.0.0后则可以远程访问)
# ---------------------------- Network ------------------------------
# 默认只允许本机访问,修改为0.0.0.0后则可以远程访问
network.host: 0.0.0.0

在这里插入图片描述

  • 进入elasticsearch/bin目录运行
[es@localhost elasticsearch-7.6.1]# cd /usr/local/elasticsearch-7.6.1/bin
[es@localhost elasticsearch-7.6.1]# ./elasticsearch

3.3 启动错误问题总结

  • 错误1:内核过低在这里插入图片描述
    我们使用的是centos6,其linux内核版本为2.6。而Elasticsearch的插件要求至少3.5以上版本。不过没关系,我们禁用这个插件即可。
    修改elasticsearch.yml文件,在最下面添加如下配置

    bootstrap.system_call_filter: false
    

    然后重启

  • 错误2:⽂件权限不足
    在这里插入图片描述
    我们用的是es用户,⽽不是root,所以文件权限不⾜。
    ⾸先⽤root⽤户登录,然后修改配置⽂件

    vim /etc/security/limits.conf
    

    添加下面的内容:

    * soft nofile 65536
    * hard nofile 131072
    * soft nproc 4096
    * hard nproc 4096
    
  • 错误3:线程数不够

     [1]: max number of threads [1024] for user [es] is too low, increase to at least[4096]
    

    这是线程数不够
    继续修改配置

    vim /etc/security/limits.d/20-nproc.conf
    

    修改下⾯的内容:

    soft nproc 1024
    #  改为
    soft nproc 4096
    
  • 错误4:进程虚拟内存(要在root用户下操作)

    [3]: max virtual memory areas vm.max_map_count [65530] likely too low, increase to at least[262144]
    

    vm.max_map_count:限制⼀个进程可以拥有的VMA(虚拟内存区域)的数量
    继续修改配置⽂件, vim /etc/sysctl.conf 添加下⾯内容:

    vm.max_map_count=655360
    

    修改完成之后在终端执行重启

    ##然后执⾏命令
    sysctl -p
    
  • 错误5:未设置节点

    the default discovery settings are unsuitable for production use; at least one of
    [discovery.seed_ho...]
    

    修改elasticsearch.yml

    cluster.name: my-application
    node.name: node-1
    cluster.initial_master_nodes: ["node-1"]
    

四、安装Kibana

Kibana是⼀个基于Node.js的Elasticsearch索引库数据统计工具,可以利用Elasticsearch的聚合功能,生成各种图表,如柱形图,线状图,饼图等。
而且还提供了操作Elasticsearch索引数据的控制台,并且提供了⼀定的API提示,⾮常有利于我们学习Elasticsearch的语法。

在这里插入图片描述

  • 安装
    kibana版本与elasticsearch保持⼀致,也是7.6.1解压到特定目录即可

    tar -zxvf kibana-7.6.1-linux-x86_64.tar.gz
    
  • 配置
    进⼊安装目录下的config⽬录,修改kibana.yml文件:

    server.port: 5601
    server.host: "0.0.0.0
    
  • 运行
    进⼊安装目录下的bin目录启动

    ./kibana
    

发现kibana的监听端⼝是5601
我们访问:http://47.96.11.185:5601
在这里插入图片描述

五、安装IK分词器(Linux)

5.1 安装

  • 在本地将下载的IK分词器压缩包解压到当前文件夹
    在这里插入图片描述
  • 将解压后的文件夹上传到云主机plugins文件夹中
    在这里插入图片描述
  • 重启es
    [es@theo bin]$ ./elasticsearch
    

5.2 测试

  • 按ik_smart方式将“千锋武汉”分词,结果为“千” “峰” “武汉”
    在这里插入图片描述

5.2 配置自定义词库(3种方式)

  • 在elasticsearch-analysis-ik-7.6.1/plugins/ik/config⽬录中定义词典⽂件(.dic)
  • 在词典⽂件中定义⾃定义词汇
  • elasticsearch-analysis-ik-7.6.1/plugins/ik/config/IKAnalyzer.cfg.xml加载⾃定义词典⽂件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
 <comment>IK Analyzer 扩展配置</comment>
 <!--⽤户可以在这⾥配置⾃⼰的扩展字典 -->
 <entry key="ext_dict">mywords.dic</entry>
 <!--⽤户可以在这⾥配置⾃⼰的扩展停⽌词字典-->
 <entry key="ext_stopwords"></entry>
 <!--⽤户可以在这⾥配置远程扩展字典 -->
 <!-- <entry key="remote_ext_dict">words_location</entry> -->
 <!--⽤户可以在这⾥配置远程扩展停⽌词字典-->
 <!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>

六、ES基本操作

ES是基于RESTful实现访问
不同操作需要使用不同的请求方式
基于REST的基本访问规范

在这里插入图片描述

6.1 数据类型

es中⼀个document表示⼀条记录,记录中field值的存储是有类型的

  • string
    text 可分词
    keyword 不能分词

  • Numeric datatypes
    long , integer , short , byte , double , float , half_float , scaled_float

  • Date datatype
    data — 日期的存储时以 long 类型存储的毫秒数

  • Boolean datatype
    boolean — true | false | “true” | “false”

  • Binary datatype
    binary 基于base64编码的字符串

  • Range datatypes
    integer_range , float_range , long_range , double_range , date_range

6.2 创建

//创建Index索引并指定field类型
PUT index4
{
 "mappings": {
 	 //设置存储在哪个分⽚上(可以不设置该字段,默认1)
	 "settings": {
	 "number_of_shards": 2
	 }
	 //设置索引属性
	 "properties": {
		 "bookId":{
		 "type": "long"
		 },
		 "bookName":{
		 "type": "text"
		 },
		 "author":{
		 "type": "keyword"
		 },
		 "time":{
		 "type": "date"
		 }
	 }
 }
}

6.3 添加

POST index4/_doc/1
{
 "bookId":10001,
 "bookName":"Java程序设计",
 "author":"张三",
 "time":234567890
}

6.4 修改

//使⽤新增操作post的请求覆盖原记录
POST index1/_doc/103
{
 "book_id":103,
 "book_name":"Python王者归来",
 "book_author":"杰哥",
 "book_price":33.22,
 "book_desc":"Python从⼊⻔到放弃"
  }
//使⽤_update修改
POST index1/_doc/103/_update
{
 "book_id":103,
 "book_name":"Python王者归来",
 "book_author":"杰哥",
 "book_price":33.22,
 "book_desc":"Python从⼊⻔到放弃"
  }

6.5 删除

DELETE index1/_doc/103

6.6 查询

# 查询索引信息
GET index4
# 查询索引的mappings信息
GET index4/_mappings
# 查询索引的属性设置
GET index4/_settings

在这里插入图片描述

  • term和terms

用于对keyword字段进行精确匹配,搜索之前不会对关键字进行分词

//查询field类型keyword的author字段是“张三”的
GET /index3/_search
{
 "query": {
	 "term": {
		 "author": "张三"
	 }
 }
}
//查询field类型keyword的author字段是“张三”或者“李四”的
GET /index3/_search
{
 "query": {
	 "terms": {
		 "author": ["张三","李四"]
	 }
 }
}
  • match查询(重点)

match查询表示对text字段进行部分匹配(模糊查询),搜索之前会对关键词进行分词

GET /index4/_search
{
 "query": {
	 "match": {
	 	"bookName": "Java程序"
	 }
 }
}
//match_all 表示查询全部内容,不指定任何条件
GET /index4/_search
{
 "query": {
 	"match_all": {}
 }
}
//multi_match 在多个字段中匹配同同时还有关键字的
GET /index4/_search
{
 "query": {
	 "multi_match": {
		 "query": "Java",
		 "fields": ["bookName","author"]
	 }
 }
}
  • 高亮显示(重点)

对匹配的关键词进行特殊样式的标记

GET /index3/_search
{
 "query": {
	 "match": {
	 	"bookName": "Java"
	 }
	},
	//对查询出来的bookName字段的值进行红色字体显示
 "highlight": {
	 "fields": {
	 	"bookName": {}
	 },
	 "pre_tags": "<label style='color:red'>",
	 "post_tags": "</label>"
 	}
}
  • 根据id查询
//根据⼀个id查询⼀个document
GET /index4/_doc/1

//根据多个id查询多个document ==> select * from ... where id in [1,2,3]
GET /index4/_search
{
 "query":{
	 "ids":{
		 "values":["1","2","3"]
	 }
 }
}
  • 其他查询
//prefix查询,根据指定字段的前缀值进⾏查询
GET /index4/_search
{
 "query": {
	 "prefix": {
		 "author": {
		 	"value": "张"
		 }
	 }
 }
}

//fuzzy查询,模糊查询,输⼊⼤概的内容es检索相关的数据
GET /index4/_search
{
 "query": {
	 "fuzzy": {
		 "bookName": {
			 "value": "jav"
		 }
	 }
 }
}

//wildcard查询:正则匹配
GET /index4/_search
{
 "query": {
	 "wildcard": {
		 "author": {
			 "value": "张*"
		 }
	 }
 }
}

//range查询,根据范围进⾏查询
GET /index4/_search
{
 "query": {
	 "range" : {
		 "bookId" : {
			 "gt" : 10001,
			 "lte" : 10003
		 }
	 }
 }
}

//分⻚查询(查询从第一天数据开始每页20条 显示"bookId","bookName"字段信息)
GET /index4/_search
{
 "query": {
	 "match_all": {}
 },
 "_source": ["bookId","bookName"],
 "from": 0,
 "size": 20
}
  • 复合查询—bool

复合查询——多条件查询

  • should ==> or 满足其一
  • must ==> and 同时满足
  • must_not ==> not 不是
GET /index4/_search
{
 "query": {
	 "bool":{
		 "must_not": [
			 {
			 "match": {
				 "bookName": "Java"
			 }
			 },
			 {
		 	"match": {
			 	"author": "张三"
			 }
		 	}
		 ]
	 }
  }
}
  • 结果过滤—filter

filter——根据条件进⾏查询,不计算分数,会对经常被过滤的数据进⾏缓存

GET /index3/_search
{
 "query": {
	 "bool":{
		 "filter": [
		 {
			 "match": {
				 "bookName": "Java"
			 }
		 },
		 {
			 "match": {
				 "author": "张三"
			 }
			}
		 ]
		}
	 }
}

七、SpringBoot整合ES

官⽅参考地址 https://www.elastic.co/guide/en/elasticsearch/client/index.html

7.1 添加es的依赖

<dependency>
	 <groupId>org.springframework.boot</groupId>
	 <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>

7.2 添加配置

spring:
 elasticsearch:
	 rest:
		 uris: http://47.96.11.185:9200
  • 如果是SSM项目则添加配置类
@Bean
public RestHighLevelClient getRestHighLevelClient(){
	//添加es所在Linux的公网ip和端口号及协议
	 HttpHost httpHost = new HttpHost("47.96.11.185", 9200, "http");
	 RestClientBuilder restClientBuilder = RestClient.builder(httpHost);
	 RestHighLevelClient restHighLevelClient = new RestHighLevelClient(restClientBuilder);
	 return restHighLevelClient; 
}

7.3 使用操作

@SpringBootTest
class Esdemo3ApplicationTests {
	//注入restHighLevelClient对象
	 @Resource
	 private RestHighLevelClient restHighLevelClient;
	 
	/**
	 * 在es中创建索引
	 */
	 @Test
	 public void testCreateIndex() throws IOException {
	 CreateIndexRequest createIndexRequest = new CreateIndexRequest("index4");
	 CreateIndexResponse createIndexResponse =
	restHighLevelClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);
	//b 为判断是否添加成功
	 boolean b = createIndexResponse.isAcknowledged);
	 }
	 
	 /**
	 * 删除索引
	 */
	 @Test
	 public void testDeleteIndex() throws IOException {
	 DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest("index4");
	 AcknowledgedResponse deleteIndexRes =
	restHighLevelClient.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);
	//b 为判断是否删除成功
	 boolean b = deleteIndexRes.isAcknowledged);
	 }
	 
	 /**
	 * 添加⽂档:将数据存⼊es
	 */
	 @Test
	 public void testCreateDocument() throws IOException {
	 Book book = new Book(10005,"平凡的世界","路遥",new Date().getTime());
	 //将book对象转换为json字符串格式存入es
	 ObjectMapper objectMapper = new ObjectMapper();
	 String jsonStr = objectMapper.writeValueAsString(book);
	 IndexRequest request = new IndexRequest("index3");
	 //设置文档id
	 request.id("10005");
	 request.source(jsonStr, XContentType.JSON);
	 IndexResponse indexResponse = restHighLevelClient.index(request,RequestOptions.DEFAULT);
	 System.out.println(indexResponse);
	 }
	 
	 /**
	 * 搜索
	 */
	 @Test
	 public void testSearch() throws IOException {
	 SearchRequest searchRequest = new SearchRequest("index3");
	 //设置搜索条件内容searchSourceBuilder 
	 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
	 //查询显示分页条件
	 searchSourceBuilder.from(0);
	 searchSourceBuilder.size(10);
	 //查询全部字段
     // searchSourceBuilder.query(QueryBuilders.matchAllQuery());
	 //查询部分字段
	 searchSourceBuilder.query(QueryBuilders.matchQuery("bookName","Java"));
	 //设置高亮字段条件highlightBuilder 
	 HighlightBuilder highlightBuilder = new HighlightBuilder();
	 HighlightBuilder.Field highlightTitle = new HighlightBuilder.Field("bookName"); 
	 highlightBuilder.preTags("<label style='color:red'>");
	 highlightBuilder.postTags("</label>");
	 
	 searchSourceBuilder.highlighter(highlightBuilder);
	 searchRequest.source(searchSourceBuilder);
	 SearchResponse searchResp = restHighLevelClient.search(searchRequest,RequestOptions.DEFAULT);
	 //查询到结果hits 可使用迭代器遍历
	 SearchHits hits = searchResp.getHits();
	 
	 //查询数据封装
	 Iterator<SearchHit> iterator = hits.iterator();
	 List<Product> products = new ArrayList<>();
	 while(iterator.hasNext()){
	 SearchHit searchHit = iterator.next();
	 String str = searchHit.getSourceAsString();
	 //将json字符串转换为对象
	 Product product = objectMapper.readValue(str, Product.class);
	 //获取高亮字段(是一个数组)
	 HighlightField highlightField = searchHit.getHighlightFields().get("productName");
	 if(highlightField != null){
	 String s = Arrays.toString(highlightField.fragments());
	 //将高亮字替换原属性
	 product.setProductName(s);
	 }
	 products.add(product);
	}
	 
	 }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值