ElasticSearch—搜索引擎

ElasticSearch—搜索引擎,第1张

ElasticSearch—搜索引擎 一、ElasticSearch简介 1.1 ElasticSearch vs Lucene的关系

ElasticSearch vs Lucene的关系,简单⼀句话就是,成品与半成品的关系。
(1)Lucene专注于搜索底层的建设,而ElasticSearch专注于企业应用。
(2)Luncene是单节点的API,ElasticSearch是分布式的—为集群而⽣。
(3)Luncene需要⼆次开发,才能使用。不能像百度或谷歌⼀样,它只是提供⼀个接⼝需要被实现才能使用, 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加载⾃定义词典⽂件




 IK Analyzer 扩展配置
 
 mywords.dic
 
 
 
 
 
 

六、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": ""
 	}
}

根据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的依赖

	 org.springframework.boot
	 spring-boot-starter-data-elasticsearch

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;
	 
	
	 @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);
	 }
	 
	 
	 @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("");
	 
	 searchSourceBuilder.highlighter(highlightBuilder);
	 searchRequest.source(searchSourceBuilder);
	 SearchResponse searchResp = restHighLevelClient.search(searchRequest,RequestOptions.DEFAULT);
	 //查询到结果hits 可使用迭代器遍历
	 SearchHits hits = searchResp.getHits();
	 
	 //查询数据封装
	 Iterator iterator = hits.iterator();
	 List 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);
	}
	 
	 }
}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5705300.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存