一、搜索流程
一般来说,搜索分为2部分
- 搜索引擎搜索:网上的资源,如百度、谷歌
- 站内搜索:本公司数据库中的数据,如淘宝、京东
一般就是从数据库里面查找,然后定期往里面添加数据
二、ElasticSearch简介
1、概述
Elasticsearch是一个实时的分布式搜索和分析引擎。它可以帮助你用前所未有的速度去处理大规模数据。ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java开发 的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。
人话:感觉像一个数据库,但是不需要写代码,写请求就行,请求和API对接
2、特点
- 可以作为一个大型分布式集群(数百台服务器)技术,处理PB级数据,服务大公 司;也可以运行在单机上
- 将全文检索、数据分析以及分布式技术,合并在了一起,才形成了独一无二的ES;
- 开箱即用的,部署简单
- 全文检索,同义词处理,相关度排名,复杂数据分析,海量数据的近实时处理
3、对比MySQL
三、走进ElasticSearch
1、安装
解压后,进入bin目录的cmd,执行命令elasticsearch
,就可以启动,这一步是启动服务器
其中,java开发是9300,其他的是9200,因为我们还没有做java,输入http://localhost:9200/
2、postman调用RestAPI
1)新建索引(数据库)
put方式地址/索引名
http://127.0.0.1:9200/tensquare_elasticsearch
2)新建文档(列)
post方式地址/索引(数据库)/类型(表)
,输入json的body,这里的body相当于一列。其中,会随机生成一个"_id"
的值
http://127.0.0.1:9200/tensquare_elasticsearch/article
3)查询全部文档(列)
GET方式地址/索引(数据库)/类型(表)/_search
http://127.0.0.1:9200/tensquare_elasticsearch/article/_search
4)修改文档
正常地修改
PUT方式地址/索引(数据库)/类型(表)/_id值
,并且传入修改过后的body的JSON格式
http://127.0.0.1:9200/tensquare_elasticsearch/article/AXXbxviVY54hHkbLjZoO
前:
后:
修改一个不存在的ID
ID是随机的,我们修改一个_id为1的,因为数据库中没有,搜索会发生什么?
http://127.0.0.1:9200/tensquare_elasticsearch/article/1
会新建一个列
5)按ID查询文档(列)
GET方式地址/索引(数据库)/类型(表)/_id值
http://127.0.0.1:9200/tensquare_elasticsearch/article/1
6)基本匹配查询
GET方式地址/索引(数据库)/类型(表)/_search?q=下标:查找值
http://127.0.0.1:9200/tensquare_elasticsearch/article/_search?q=content:好玩
这个是基本匹配查询,照例来说应该是按照全部去查找而不是查找其中一部分就可以。这是因为这个引擎的基本匹配查找是按字段查找的,而每一个汉字都是一个字段,就是说每一个汉字都可以通过模糊查找。
但是英文不行,英文的一个字段是一个单词或者字母开头遇到非字母结束的那段东西,所以搜索Jav查找不到任何东西,而查找Java能查找东西
7)模糊查找
GET方式地址/索引(数据库)/类型(表)/_search?q=下标:*查找值*
http://127.0.0.1:9200/tensquare_elasticsearch/article/_search?q=content:*av*
8)删除文档(列)
DELET方式地址/索引(数据库)/类型(表)/_id号*
http://127.0.0.1:9200/tensquare_elasticsearch/article/1
四、head
1、概述
这是个对ElasticSearch进行前端界面化的工具,需要先安装node.js
2、安装
-
下载head插件:https://github.com/mobz/elasticsearch-head
-
解压
-
安装node.js,安装cnpm(提高速度)
npm install -g cnpm --registry=https://registry.npm.taobao.org
-
npm install -g grunt -cli
这个我也不知道是啥,做就对了
-
安装依赖(进入head的安装目录中,主要有package.json这个就行)
cnpm install
-
在head目录中启动head
grunt server
这里给地址了,进入 http://localhost:9100/
这里显示未连接,原因:
- 没有打开ElasticSearch
- 跨域了
3、解决跨域问题
ElasticSearch是9200,这个head是9100,想要两者跨域,只需要在elasticsearch-5.6.8\config下的elasticsearch.yml文件尾添加
http.cors.enabled: true
http.cors.allow-origin: "*"
然后重启ElasticSearch
4、操作
这个就是各图形界面化而已啦,不是软件而是浏览器的形式展示,请求什么的都一样
五、IK分词器
1、概述
没错,还要下东西,已经下了ElasticSearch搜索引擎,界面化的head,而IK分词器就是帮助我们分词的。
由于我原本没有学过ElasticSearch,所以不知道原生的分词器是怎样的(分词器就是输入一段话把其中的词拆分出来进行搜索),但是有示例,比如用原生的分词器就是
地址/_analyze?analyzer=chinese&&pretty=true&text=要搜索的词
要是搜索英文的词
http://127.0.0.1:9200/_analyze?analyzer=chinese&pretty=true&text=i am good
这样挺正常
要是搜索的是中文
http://127.0.0.1:9200/_analyze?analyzer=chinese&pretty=true&text=我是程序员
结果是
每一个词都分开了,这样很不符合搜索规范嘛,哪有这样分开搜索的。。。
所以,我们就要用IK分词器为我们提供分词,其包含了普通的词进行分词,也支持自定义分词
2、安装
- 下载,解压,重命名为ik
- 拷贝到elasticsearch-5.6.8\plugins下
- 重新启动elasticsearch
3、使用
其提供了两个方法
ik_smart
为最少切分ik_max_word
为最细粒度划分
ik_smart
ik_max_word
4、自定义词库
因为词条是会随着时间的推移而更新的,这个IK12年的时候就不更新了,所以,后续的词条是要我们手动添加的
按照现在,老铁
真
给力
可以分为3个词条,需要我们自定义
-
elasticsearch-5.6.8\plugins\ik\config下,创建一个.dic文件,保存格式为UTF-8
老铁 给力
注意这里每一个词条上面和下面都要留一行空格,这是为了预防BUG出现,记住就行
-
修改elasticsearch-5.6.8\plugins\ik\config\IKAnalyzer.cfg.xml,添加文件,重新启动elasticsearch
<?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">custom.dic</entry> <!--用户可以在这里配置自己的扩展停止词字典--> <entry key="ext_stopwords"></entry> <!--用户可以在这里配置远程扩展字典 --> <!-- <entry key="remote_ext_dict">words_location</entry> --> <!--用户可以在这里配置远程扩展停止词字典--> <!-- <entry key="remote_ext_stopwords">words_location</entry> --> </properties>
六、elasticsearch7.X
1、更新换代
由于笔者看的视频是18年的,那时还是elasticsearch 5.x,底层是5.x,但是现在20年elasticsearch大多是7.x了,yml、IK词条、配置已经完全不一样了。而且,7.x没有type(表)这么一个概念了。所以,要再重新学一遍elasticsearch 7.x
2、下载
在官网下,elasticsearch和IK的版本要一致,那些安装和上面的一样,head不用变,步骤比较多,不要漏任何一步
3、postman调用RestAPI
rest一样,更加详细的在这里
4、不一样的地方
IK分词器
安装还是这么安装,但用法不一样,7.x是
GET方式 地址/_analyze?pretty=true
,body为:
{
"analyzer":"ik_smart / ik_max_word",
"下标": "查找字"
}
其他
- 7.x版本只运行一个type,后面的type不管起什么名字,都没用,都是会放在第一个type的
- 控制版本要和本地的一样,在父pom中
<properties> <java.version>1.8</java.version> <!-- 这里要一样--> <elasticsearch.version>7.10.0</elasticsearch.version> </properties>
七、微服务模块
1、导包与更新换代
- 本项目pom
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
<version>2.3.4.RELEASE</version>
</dependency>
- 父项目pom
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<!-- 这里要一样-->
<elasticsearch.version>7.10.0</elasticsearch.version>
</properties>
2、config
需要创建一个设置类
//照抄就行,官网得
@Configuration
public class ElasticsearchConfig extends AbstractElasticsearchConfiguration {
@Override
public RestHighLevelClient elasticsearchClient() {
final ClientConfiguration clientConfiguration = ClientConfiguration.builder()
.connectedTo("localhost:9200")
.build();
return RestClients.create(clientConfiguration).rest();
}
}
3、实体层
//对应elasticsearch的index 和 type
@Document(indexName = "tensquare_test")
@Data
public class Article implements Serializable {
@Id
private String id;
/*
@Field干嘛的
是否索引,就是看该域是否能被搜索(面试回答)
是否分词,就表示搜索的时候是整体匹配还是单词匹配
是否存储,就是是否在页面上显示
*/
@Field(index = true,analyzer = "ik_max_word",searchAnalyzer = "ik_max_word")
private String title;
@Field(index = true,analyzer = "ik_max_word",searchAnalyzer = "ik_max_word")
private String content;
private String state;
}
@Document(indexName = "tensquare_test")
对应哪个数据库@Field
写就对了,index=true表明这个字段可以被搜索到。另外两个都是让搜索变为IK搜索方式
4、3层设置
dao
public interface ArticleDao extends ElasticsearchRepository<Article,String> {
}
service
@Service
public class ArticleService {
@Autowired
private ArticleDao articleDao;
@Autowired
private IdWorker idWorker;
public void add(Article article){
article.setId(idWorker.nextId()+"");
articleDao.save(article);
}
public void deleteById(String id){
articleDao.deleteById(id);
}
}
controller
@RestController
@CrossOrigin
@RequestMapping("/article")
public class ArticleController {
@Autowired
private ArticleService articleService;
@PostMapping("")
public Result save(@RequestBody Article article){
articleService.add(article);
return new Result(true, StatusCode.OK,"添加成功");
}
@DeleteMapping("{id}")
public Result deleteById(@PathVariable String id){
articleService.deleteById(id);
return new Result(true,StatusCode.OK,"删除成功");
}
}
5、查询数据
传统艺能
public interface ArticleDao extends ElasticsearchRepository<Article,String> {
//查找
public Page<Article> findByTitleOrContentLike(String title, String content, Pageable p);
}
public Page<Article> findByTitleOrContentLike(String keyword,int page,int size){
Pageable pageable = PageRequest.of(page-1, size);
return articleDao.findByTitleOrContentLike(keyword,keyword,pageable);
}
@GetMapping("search/{keyword}/{page}/{size}")
public Result findByTitleOrContentLike(@PathVariable String keyword,@PathVariable int page,@PathVariable int size){
Page<Article> articles = articleService.findByTitleOrContentLike(keyword, page, size);
return new Result(true,StatusCode.OK,"查询成功",new PageResult<Article>(articles.getTotalElements(),articles.getContent()));
}
八、利用Logstash进行ES与MySQL数据同步
1、Logstash
Logstash是一款轻量级的日志搜集处理框架,可以方便的把分散的、多样化的日志搜集 起来,并进行自定义的处理,然后传输到指定的位置,比如某个服务器或者文件。
人话:ES是一个数据库,MySQL也是一个数据库,但是我们查找是用ES,但源数据的增删改用的是MySQL,而Logstash就是用来自动将MySQL的数据转移到ES的
2、Logstash安装与测试
由于Logstash5.X的我电脑运行不了,所以换了7.62版本。
至今为止,ES,Logstash,IK,都是用7.X版本的
解压,进入bin目录,cmd
logstash -f 文件路径
而其中的文件路径,就是我们用MySQL导入ES的文件,语法什么的都是固定的
这个文件起名xx.conf就行,我这里设置为根目录/mysqletc/mysql.conf,这个是模块
input {
jdbc {
# mysql jdbc connection string to our backup databse
jdbc_connection_string => ""
# the user we wish to excute our statement as
jdbc_user => ""
jdbc_password => ""
# the path to our downloaded jdbc driver
jdbc_driver_library => ""
# the name of the driver class for mysql
jdbc_driver_class => "com.mysql.jdbc.Driver"
jdbc_paging_enabled => ""
jdbc_page_size => ""
#以下对应着要执行的sql的绝对路径。
#statement_filepath => ""
statement => ""
#定时字段 各字段含义(由左至右)分、时、天、月、年,全部为*默认含义为每分钟都更新(测试结果,不同的话请留言指出)
schedule => "* * * * *"
}
}
output {
elasticsearch {
#ESIP地址与端口
hosts => ""
#ES索引名称(自己定义的)
index => ""
#自增ID编号
document_id => "%{id}"
document_type => ""
}
stdout {
#以JSON格式输出
codec => json_lines
}
}
这个是正文
input {
jdbc {
# mysql jdbc connection string to our backup databse
#这个是MySQL的数据库,就是之前article的yml的MySQL数据源
##注意要加useSSL=false
jdbc_connection_string => "jdbc:mysql://192.168.12.128:3306/tensquare_article?characterEncoding=UTF8&useSSL=false"
# the user we wish to excute our statement as
#账号
jdbc_user => "root"
#密码
jdbc_password => "root"
# the path to our downloaded jdbc driver
#MySQL连接Java的jar包,自己下载
jdbc_driver_library => "D:\tools\logstash-7.6.2\mysqletc\mysql-connector-java-5.1.46.jar"
# the name of the driver class for mysql
jdbc_driver_class => "com.mysql.jdbc.Driver"
#是否分页
jdbc_paging_enabled => "true"
#分页数据大小
jdbc_page_size => "50000"
#以下对应着要执行的sql的绝对路径。
#下面写查询语句,将该查询语句导入ES中
#statement_filepath => ""
statement => "SELECT id,title,content,state FROM tb_article"
#定时字段 各字段含义(由左至右)分、时、天、月、年,全部为*默认含义为每分钟都更新(测试结果,不同的话请留言指出)
#全是*,就是每分钟更新一次
schedule => "* * * * *"
}
}
output {
elasticsearch {
#ESIP地址与端口
hosts => "127.0.0.1:9200"
#ES索引名称(自己定义的)
index => "tensquare_article"
#自增ID编号
document_id => "%{id}"
document_type => "_doc"
}
stdout {
#以JSON格式输出
codec => json_lines
}
}
- 注意点:数据源要加入
useSSL=false
然后在bin中输入logstash -f ../mysqletc/mysql.conf
已经开始更新了
但是!我们至今为止做的操作,ES和Logstash是本地的,用本地做测试一遍,就先不会晕,接下来就是在docker中操作了
3、特性
虽然很美好,但还是有缺点的,在MySQL中删除的东西,同步到Logstash中并不会删除,还是会在Logstash保存记录的。而我们的做法一般都是Logstash只做查询不做增删改。
- 解决方法:MySQL中,删除一个数据不要真的删,添加一个列state,为0就表示删除,1表示没被删除,这样,查的时候就查询state=1的值就行。
九、docker中安装与运行
docker的国内加速在我之前的docker文章中有说
1、ES
注意我们要用ES 7.X的,如果默认下载lates,就只会是5.x
1)安装
安装的版本链接
看版本是什么,我用的是
docker pull elasticsearch:7.9.3
2)创建容器
docker run -di --name=tensquare_es -p 9200:9200 -p 9300:9300 elasticsearch:7.9.3
3)一系列的BUG与解决
参考链接:
https://blog.csdn.net/qq_43511351/article/details/105283867
https://blog.csdn.net/qq_43655835/article/details/104637625
①系统调优
这样创建了并且启动了,但是!这样会因为默认JVM内存不够而自动关掉
修改/etc/security/limits.conf ,追加内容
vi /etc/security/limits.conf
,添加
* soft nofile 65536
* hard nofile 65536
nofile是单个进程允许打开的最大文件个数 soft nofile 是软限制 hard nofile是硬限制
修改/etc/sysctl.conf,追加内容
vi /etc/sysctl.conf
,追加内容
vm.max_map_count=655360
执行命令,重启虚拟机
执行这条命令sysctl ‐p
然后手动重启
②出现新的BUG
看BUG是啥
原本以为,弄好上面的内存大小,就好了,没想到一启动,还是错,查看错误日志
docker logs -f 容器ID
出现错误
ERROR: [1] bootstrap checks failed
[1]: the default discovery settings are unsuitable for production use; at least one of [discovery.seed_hosts, discovery.seed_providers, cluster.initial_master_nodes] must be configured
ERROR: Elasticsearch did not exit normally - check the logs at /usr/share/elasticsearch/logs/docker-cluster.log
翻译过来就是默认的设置不适合生产使用,意思就是你必须要配置[discovery.seed_hosts, discovery.seed_providers, cluster.initial_master_nodes]之一。然后根据上网找的资料找到下面的那条命令。。
解决步骤
只能先删除原本的镜像了
再执行命令
docker run -di --name=tensquare_es -e ES_JAVA_POTS="-Xms256m -Xmx256m" -e "discovery.type=single-node" -p 9200:9200 -p 9300:9300 elasticsearch:7.9.3
- 这一次启动修改配置文件 第一个是修改jvm的内存 第二个是表面这个es是单个节点
访问http://192.168.12.128:9200/
看到可以访问,感动哭了,2天的BUG就快做好了
测试
修改Java文件,把ElasticsearchConfig
修改
//照抄就行,官网得
@Configuration
public class ElasticsearchConfig extends AbstractElasticsearchConfiguration {
@Override
public RestHighLevelClient elasticsearchClient() {
final ClientConfiguration clientConfiguration = ClientConfiguration.builder()
//这里改成docker的地址
.connectedTo("192.168.12.128:9200")
.build();
return RestClients.create(clientConfiguration).rest();
}
}
成功了!!!!!!
②开启远程连接
上面是连接了,但是win的head端连接不了啊。
elasticsearch 5.x版本后就默认不开启远程连接,上面的head操作的时候,是进入到elasticsearch-7.10.0\config\elasticsearch.yml添加东西的。这个思路在Linux也是一样,找到文件然后修改文件。
我的版本(新版)
查看文件docker exec -it tensquare_es /bin/bash
这个进入到容器了,查看有什么文件
有config文件夹,和win的一样,修改config\elasticsearch.yml即可
编辑vi elasticsearch.yml
,添加下列文字,保存
http.cors.enabled: true
http.cors.allow-origin: "*"
重启改容器docker restart tensquare_es
测试
启动win的head,连接
老版本
老版本不能直接进入文件里面修改的,要挂载什么的。以下是复制粘贴的文章
2、IK分词器
还没有安装IK分词器
操作是一样的,把win的IK分词器下好,再放到虚拟机中的相同目录
win是把IK文件(把自定义的也弄好了的)放到elasticsearch-7.10.0\plugins中。
Linux也一样
1)把win的IK传送到虚拟机中
注意,ES的版本要和IK的版本一模一样才可以,不然的话会错误。解决链接
用xftp,进行win和虚拟机的交互
2)把虚拟机中的IK拷贝到容器中
放到虚拟机中了,再把虚拟机中的IK文件拷贝到容器/usr/share/elasticsearch/plugins/
中
①拷贝到容器中
docker cp ik tensquare_es:/usr/share/elasticsearch/plugins/
②重启
docker restart tensquare_es
3、head
这个得先允许ES跨域,这个在之前就做了
1)下载安装
下载header7.x(5.x用不了)
docker pull mobz/elasticsearch-head:5
创建容器
docker run -di --name=tensquare_header -p 9100:9100 mobz/elasticsearch-head:5
2)有BUG
这里可以进去,但是查不到数据
3)解决BUG
原因:
elasticsearch 6增加了请求头严格校验的原因,并且返回结果是
{
“error” : “Content-Type header [application/x-www-form-urlencoded] is not supported”,
“status” : 406
}
进入head插件安装目录 ,编辑/usr/src/app/_site/vendor.js
容器编辑不了点击链接
修改共有两处:
第6886行 : contentType: “application/x-www-form-urlencoded”
改为 contentType: “application/json;charset=UTF-8”
第7573行: var inspectData = s.contentType === “application/x-www-form-urlencoded” &&
改为 var inspectData = s.contentType === “application/json;charset=UTF-8” &&
PS:
vim中显示行号的命令为
:set nu
vim中跳转到指定行的命令为
:行号(esc 再: ,再输入,6886)