ES搜索引擎
☣ ☣
一、Kibana
一款开源的数据分析和可视化平台,此处不做主要介绍
二、IK Analysis 中文分词器
- Es的常用插件之一
- IK Analysis插件将Lucene IK分析器集成到elasticsearch中,支持自定义词典。
1、单机配置
官网下载地址
① 安装配置
直接上传资源到linux,解压指定位置,并进行授权
# 创建ik目录
mkdir -p /usr/local/elasticsearch/es1/elasticsearch-7.4.2/plugins/ik
# 解压至ik目录
unzip elasticsearch-analysis-ik-7.4.2.zip -d /usr/local/elasticsearch/es1/elasticsearch-7.4.2/plugins/ik/
#授权个es账户
chown -Rf es:es /usr/local/elasticsearch/
重启ES,测试
② 测试
直接创建索引库和设置mapping
# 创建索引库
curl -X PUT http://localhost:9200/ik -H 'Content-Type:application/json' - d'{
"settings": {
"number_of_shards": 5,
"number_of_replicas": 1
}
}'
# 设置mapping
# Analyzer分词配置解释:
#ik_smart:粗粒度分词,比如中华人民共和国国歌,会拆分为中华人民共和国,国歌;
#ik_max_word:细粒度分词,比如中华人民共和国国歌,会拆分为中华人民共和国,中华
#人民,中华,华人,人民共和国,人民,人,民,共和国,共和,和,国国,国歌,会穷
#尽各种可能的组合。
插入数据
curl -XPOST http://localhost:9200/ik/_create/1 -H 'Content- Type:application/json' -d' {"content":"美国留给伊拉克的是个烂摊子吗"} '
curl -XPOST http://localhost:9200/ik/_create/2 -H 'Content- Type:application/json' -d' {"content":"公安部:各地校车将享最高路权"} '
curl -XPOST http://localhost:9200/ik/_create/3 -H 'Content- Type:application/json' -d' {"content":"中韩渔警冲突调查:韩警平均每天扣1艘中国渔船"} '
curl -XPOST http://localhost:9200/ik/_create/4 -H 'Content- Type:application/json' -d' {"content":"中国驻洛杉矶领事馆遭亚裔男子枪击 嫌犯已自首"} '
启动Es(启动es要切换到es用户下)和head客户端查看结果:
这里看出,es自动加载了插件ik
进行数据索引查询
三、Elasticsearch导入MySQL数据
1、安装Mysql⭐
本文使用5.7.2X版本,如果找不到对应的版本信息,可以通过该地址获取: 下载(es可以说是一个非关系型数据库)
安装
yum -y install mysql57-community-release-el7.rpm
yum -y install mysql-community-server
#如果报错则更新wget
yum -y install wget
#启动查看服务器状态
systemctl start mysqld
systemctl status mysqld
这种安装方式会将MySQL添加至环境变量和启动服务
如果安装后启动失败:
#查看是否安装过数据库
rpm -qa|grep mysql
#删除以前安装的数据库
rpm -e 数据库文件名
#查看数据库安装后的目录
find / -name mysql
find / -name mysqld
#在重新安装
2、修改密码和配置
修改密码并授权
#获取安装后提供的密码
grep "password" /var/log/mysqld.log
#登录数据库
mysql -u root –p
#修改密码规则
set global validate_password_policy=0;
set global validate_password_length=4;
#修改密码
set password = password('root');
#退出重新进入
授权
# 改表法
# 选择数据库
use mysql;
# 最后授权MySQL,允许远程用户登录访问
MySQL update user set host = '%' where user = 'root';
# 刷新权限
flush privileges;
# 授权法
# 允许192.168.10.105(linuxIP地址)连接访问所有库的所有表(*.*),连接密码为1234
GRANT ALL PRIVILEGES ON *.* TO 'root'@'192.168.10.105' IDENTIFIED BY '1234' WITH GRANT OPTION;
# 允许所有连接访问所有库的所有表(*.*),连接密码为1234
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '1234' WITH GRANT OPTION;
# 刷新权限
FLUSH PRIVILEGES;
#关闭防火墙
systemctl stop firewalld
#查看防火墙状态
systemctl status firewalld
一定要设置防火墙,否则windons客户端无法访问
3、数据库忘记密码
忘记密码的修改方法
# 展示所有数据库
show databases;
# 选择数据库
use mysql;
# 展示所有表
show tables;
# 忘记密码后修改密码
# 第一步的作用是启动时跳过验证
1. vi /etc/my.cnf在[mysqld]里加入skip-grant-tables
2. 重启mysql服务,连接mysql无密码登入use mysql;选择数据库
3. 敲下面这行代码修改密码 update mysql.user set authentication_string=password('root') where user='root';
4. vi /etc/my.cnf在[mysqld]里删除skip-grant-tables 重启mysql服务,新密码登录即可
4、安装Logstash
Logstash 是开源的服务器端数据处理管道,能够同时从多个来源采集数据,转换数据,然后将数据发送到您最喜欢的 “存储库” 中,Logstash技术,导入数据,实现数据录入,数据处理管道。下载地址
① 安装与测试
直接安装
#创建安装目录
mkdir -p /usr/local/logstash
#解压
tar -zxvf logstash-7.4.2.tar.gz -C /usr/local/logstash/
安装
cd /usr/local/logstash/logstash-7.4.2
bin/logstash -e 'input { stdin {} } output { stdout {} }'
成功运行输入helloworld返回一个helloworld就成功了
② 同步mysql数据
上传一个驱动jar,和两个配置文件jdbc.conf,jdbc.sql
#注意:请将mysql的驱动包上传至 logstash-7.4.2/logstash-core/lib/jars/ 目录下
/usr/local/logstash/logstash-7.4.2/logstash-core/lib/jars/
# jdbc.conf
# cd /usr/local/logstash/logstash-7.4.2
# vim jdbc.conf
jdbc {
# 配置数据库信息
jdbc_connection_string => "jdbc:mysql://192.168.168.129:3306/shop?useUnicode=true&cha
racterEncoding=UTF-8&useSSL=false" jdbc_driver_class => "com.mysql.jdbc.Driver"
jdbc_user => "root"
jdbc_password => "1234"
jdbc_paging_enabled => "true"
jdbc_page_size => "50000"
# 执行 sql 语句文件
statement_filepath => "/usr/local/logstash/logstash-7.4.2/jdbc.sql"
# 定时字段 各字段含义(由左至右)分、时、天、月、年,全部为*默认含义为每分钟都更新
schedule => "* * * * *"
# 是否将 sql 中 column 名称转小写
lowercase_column_names => false
}
}
output {
elasticsearch {
hosts => ["192.168.168.129:9200"]
index => "shop"
# 文档_id,%{goods_id}意思是取查询出来的goods_id的值,并将其映射到es的_id字段中
# 文档_id,%{goodsId}如果是别名,意思是取查询出来的goodsId的值,并将其映射到es的_id
字段中 document_id => "%{goodsId}"
}
stdout {
codec => json_lines
}
}
--------------------------------------------------------------
# jdbc.sql
SELECT
goods_id goodsId,
goods_name goodsName,
market_price marketPrice,
original_img originalImg
FROM
t_goods
# 检测配置文件是否编写正确
bin/logstash -f /usr/local/logstash/logstash-7.4.2/jdbc.conf -t
③ 创建索引库shop与mapping
索引库
mapping:
# 执行数据导入(前提是数据库中shop数据库有数据)
cd /usr/local/logstash/logstash-7.4.2/
#配置文件回去直接调用jdbc.sql语句将查出来的数据导入到es中
bin/logstash -f /usr/local/logstash/logstash-7.4.2/jdbc.conf
#导入较慢
最终结果
查询测试:
四、Elasticsearch的JavaAPI
整合IDEA
1、创建项目并配置、测试
Elasticsearch有两种连接方式: transport 、 rest,ES官方建议使用 rest 方式,
- 直接创建一个maven,java项目引入依赖
<dependencies>
<!-- junit 单元测试依赖 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- elasticsearch 服务依赖 -->
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>7.4.2</version>
</dependency>
<!-- rest-client 客户端依赖 -->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
<version>7.4.2</version>
</dependency>
<!-- rest-high-level-client 客户端依赖 -->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.4.2</version>
</dependency>
</dependencies>
创建测试类测试:
//连接服务器
public class EsTest {
// ES服务器IP
private final static String HOST = "192.168.168.129";
// ES服务器连接方式
private final static String SCHEME = "http";
// 初始化 ES 服务器集群
// 参数分别为:IP,端口,连接方式(默认为http)
private final static HttpHost[] httpHosts = {
new HttpHost(HOST, 9200, SCHEME)
};
//客户端
private RestHighLevelClient client=null;
/*** 获取客户端 */
@Before
public void getConnect() {
client = new RestHighLevelClient(RestClient.builder(httpHosts));
}
/*** 关闭连接 */
@After
public void closeConnect() {
try {
if (null != client)
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/*** 查询数据 */
@Test
public void testRetrieve() throws IOException {
// 指定索引库和id
GetRequest getRequest = new GetRequest("ik", "4");
// 执行请求
GetResponse getResponse = client.get(getRequest, RequestOptions.DEFAULT);
System.out.println(getResponse.getSource());
}
/*** 添加数据 */
@Test
public void testCreate() throws IOException {
// 准备数据
Map<String, Object> jsonMap = new HashMap<>();
jsonMap.put("username", "zhangsan");
jsonMap.put("age", 18);
jsonMap.put("address", "sh");
// 指定索引库和id及数据
IndexRequest indexRequest = new IndexRequest("ik").id("5").source(jsonMap);
//执行请求
IndexResponse indexResponse = client.index(indexRequest, RequestOptions.DEFAULT);
System.out.println(indexResponse.toString());
}
/*** 修改数据 */
@Test
public void testUpdate() throws IOException {
// 准备数据
Map<String, Object> jsonMap = new HashMap<>();
jsonMap.put("username", "lisi"); jsonMap.put("age", 20);
jsonMap.put("address", "bj");
// 指定索引库和id及数据
UpdateRequest updateRequest = new UpdateRequest("ik", "5").doc(jsonMap);
// 执行请求
UpdateResponse updateResponse = client.update(updateRequest, RequestOptions.DEFAULT);
System.out.println(updateResponse.toString());
}
/*** 批量查询-分页查询-高亮查询 */
@Test
public void testHighlight() throws IOException {
// 指定索引库
SearchRequest searchRequest = new SearchRequest("shop");
// 构建查询对象
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
// 添加分页条件,从第 0 个开始,返回 5 个
searchSourceBuilder.from((5-1)).size(5);
// 构建高亮对象
HighlightBuilder highlightBuilder = new HighlightBuilder();
// 指定高亮字段和高亮样式
highlightBuilder
.field("goodsName")
.preTags("<span style='color:red;'>")
.postTags("</span>");
searchSourceBuilder.highlighter(highlightBuilder);
// 添加查询条件
// 指定从 goodsName 字段中查询
String key = "中国移动联通电信";
searchSourceBuilder.query(QueryBuilders.multiMatchQuery(key, "goodsName"));
// 执行请求
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
// 总条数
System.out.println(searchResponse.getHits().getTotalHits().value);
// 结果数据(如果不设置返回条数,大于十条默认只返回十条)
SearchHit[] hits = searchResponse.getHits().getHits();
for (SearchHit hit : hits) {
// 构建项目中所需的数据结果集
String highlightMessage = String
.valueOf(hit.getHighlightFields()
.get("goodsName")
.fragments()[0]);
Integer goodsId = Integer.valueOf((Integer) hit.getSourceAsMap().get("goodsId"));
String goodsName = String.valueOf(hit.getSourceAsMap().get("goodsName"));
BigDecimal marketPrice = new BigDecimal(String.valueOf(hit.getSourceAsMap().get("marketPrice")));
String originalImg = String.valueOf(hit.getSourceAsMap().get("originalImg"));
System.out.println("goodsId -> " + goodsId);
System.out.println("goodsName -> " + goodsName);
System.out.println("highlightMessage -> " + highlightMessage);
System.out.println("marketPrice -> " + marketPrice);
System.out.println("originalImg -> " + originalImg);
System.out.println("----------------------------");
}
}
}
2、SpingBooot整合ES
①、创建项目并配置
- 创建maven中java项目,引入依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
编写dao层与pojo接收对象
//dao层提供接口
public interface GoodsInter extends ElasticsearchRepository<Goods,Integer> {
/*更具商品名查询*/
public List<Goods> findByGoodsName(String goodsName);
}
//-------------------------------------------------------
//pojo
@Document(indexName = "shop",shards = 5,replicas = 1,createIndex = false)
public class Goods implements Serializable {
/*** 商品id */
@Id
private Integer goodsId;
/*** 商品名称 */
@Field(type = FieldType.Text,analyzer = "ik_max_word")
private String goodsName;
/*** 市场价 */
@Field(type = FieldType.Double)
private BigDecimal marketPrice;
/*** 商品上传原始图 */
@Field(type = FieldType.Keyword)
private String originalImg;
/*** t_goods */
private static final long serialVersionUID = 1L;
//此处省略构造器和toString set get方法
/**为需要使用索引库的实体类加上注解 @Document 部分属性如下
indexName="索引库名" shards = 分片数量(默认1) replicas = 副本数量(默认1)
为id属性 添加 @Id 注释
各个字段加上注解并制定类型 @Field 部分属性如下
type= FieldType.枚举 : 指定字段类型 Keyword不分词, Text分词 对应着
elasticsearch的字段类型
为需要分词的字段添加分词器 analyzer="分词器名" (ik分词器固定写法 ik_max_word )
是否创建索引 createIndex=boolean(默认true)**/
编写启动类
@SpringBootApplication
public class Start {
public static void main(String[] args) {
SpringApplication.run(Start.class,args);
}
}
//测试文件目录与项目文件加目录要一直,否则扫描不到启动类,导致启动失败
②、测试
编写测试类
@SpringBootTest
public class EsTest {
@Autowired
GoodsInter goodsInter;
@Autowired
private ElasticsearchRestTemplate elasticsearchRestTemplate;
/*** 根据商品名查询 */
@Test
public void testFindByName() {
List<Goods> list = goodsInter.findByGoodsName("%中国%");
list.forEach(System.out::println);
}
/*** 批量插入,查询所有 */
@Test public void testSaveAll() {
//批量插入
List<Goods> list = new ArrayList<>();
list.add(new Goods(152, "测试手机1", new BigDecimal("500"), "jpg"));
list.add(new Goods(153, "测试手机2", new BigDecimal("800"), "png"));
goodsInter.saveAll(list);
//查询所有
Iterable<Goods> all = goodsInter.findAll(); all.forEach(System.out::println);
}
/*** 索引操作 (已经纯在)*/
//等值收缩由局限性于是使用esTemplate的检索方法
@Test
public void testIndex() {
//设置索引信息(实体类),返回indexOperations
IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(Goods.class);
indexOperations.create();
//创建索引映射
Document mapping = indexOperations.createMapping();
//将映射写入索引
indexOperations.putMapping(mapping);
//获取索引
Map<String, Object> map = indexOperations.getMapping();
map.forEach((k, v) -> System.out.println(k + "-->" + v));
//索引是否存在
boolean exists = indexOperations.exists(); System.out.println(exists);
//删除索引
indexOperations.delete();
}
/*** 增删改 */
@Test
public void testDocument() {
/** 根据id和索引删除,返回删除的id
* 第一个参数:id,String类型 * 第二个参数:索引库对象 */
String count = elasticsearchRestTemplate.delete("150", IndexCoordinates.of("shop"));
System.out.println(count);
/*** 删除查询结果 * 第一个参数:查询对象 * 第二个参数:索引类字节码 * 第三个参数:索引库对象 */
elasticsearchRestTemplate.delete( new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.matchQuery("goodsName", "测试"))
.build(), Goods.class, IndexCoordinates.of("shop"));
//新增/更新(id不存在就新增,存在就更新)
List<Goods> list = new ArrayList<>();
list.add(new Goods(150, "测试手机3", new BigDecimal("100"), "jpg"));
list.add(new Goods(151, "测试手机4", new BigDecimal("200"), "png"));
Iterable<Goods> save = elasticsearchRestTemplate.save(list);
save.forEach(System.out::println);
}
/*** 匹配查询 */
@Test
public void testSearchMatch() {
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
NativeSearchQuery query = nativeSearchQueryBuilder
/*** 第一个参数:关键词 * 第二个参数:对应es的字段 */
.withQuery(QueryBuilders.multiMatchQuery("中国移动联通电信", "goodsName"))
.build(); SearchHits<Goods> search = elasticsearchRestTemplate.search(query, Goods.class);
search.forEach(searchHit -> System.out.println(searchHit.getContent()));
}
/*** 分页,排序,高亮查询 */
@Test
public void testSearchPage() {
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
NativeSearchQuery query = nativeSearchQueryBuilder
/*** 第一个参数:关键词 * 第二个参数:对应es的字段 */
.withQuery(QueryBuilders.multiMatchQuery("中国移动联通电 信", "goodsName"))
/*** 第一个参数:当前页,0开始 * 第二个参数:每个条数 * 第三个参数:排序对象 * 升序/降序 * 比较字段 */
//.withPageable(PageRequest.of(0, 5, Sort.Direction.DESC, "goodsId", "marketPrice"))
// 分页
.withPageable(PageRequest.of(0, 5))
//.withSort(SortBuilders.fieldSort("marketPrice").order(SortOrder.ASC))
//高亮,默认样式<em></em>(斜体)
//.withHighlightFields(new HighlightBuilder.Field("goodsName"))
//高亮,指定样式
.withHighlightBuilder(new HighlightBuilder()
.field("goodsName")
.preTags("<span style='color:red;'>")
.postTags("</span>")).build();
SearchHits<Goods> search = elasticsearchRestTemplate.search(query, Goods.class);
for (SearchHit<Goods> searchHit : search) {
//id
System.out.println(searchHit.getId());
//分数
System.out.println(searchHit.getScore());
//排序的值
Double sortValues = (Double) searchHit.getSortValues().get(0);
System.out.println(sortValues);
//高亮信息
String highlightMessage = searchHit.getHighlightField("goodsName").get(0);
System.out.println(highlightMessage);
//结果对象
System.out.println(searchHit.getContent());
System.out.println("----------------------------------------");
}
}
}
SpringBoot整合中,实现类接口ElasticsearchRepository,此接口为我们提供了很多方法,并且可以更具一些常用的需求组合出需要的方法,不需要我们手动去写实现方法,爆赞👍(精美壁纸一份)