全文检索概述
1.为什么需要ES:
因为如果我们基于数据库做搜索,那么Like的效率非常低,而且各种条件排序及其不方便,所以我们需要使用专业的搜索工具ES来完成搜索
2.什么是全文检索引擎:
就是把没有结构的数据通过检索工具转换为有结构的数据然后存储起来,在查找数据的时候根据结构的数据进行查找
3.什么是ES:
是一个分布式的全文检索引擎,底层封装了Lucene
4.ES是只处理文本不处理语义:语义是人工智能AI对话,但是ES很明显做不到,他只能通过关键字去匹配你倒排索引中的内容
什么是Lucene
Lucene是apache下的一个开源的全文检索引擎工具包(一堆jar包)。它为软件开发人员提供一个简单易用的工具包(类库),以方便的在小型目标系统中实现全文检索的功能。Lucene适用于中小型项目 ,ES适用于中大型项目(它底层是基于lucene实现的)
ES的特点
1、分布式的实时文件存储
2、分布式全文搜索引擎,每个字段都被索引并可被搜索
3、能在分布式项目/集群中使用
4、本身支持集群扩展,可以扩展到上百台服务器
5、处理PB级结构化或非结构化数据
6、简单的 RESTful API通信方式
7、支持各种语言的客户端
8、基于Lucene封装,使操作简单
ES创建索引的流程
1.给原始数据加索引
2.将原始数据进行分词,分词之后的数据对应了之前的索引
3.将所有词进行小写以及词态转换
4.对所有的此进行字母顺序排序
5.将所有的词进行去重并且合并索引,最终形成倒排索引文档
ES下载和安装
ES的安装比较简单,只需要官方下载ES的运行包,然后启动ES服务即可。ES的使用主要是通过能够发起HTTP请求的终端来接入,比如Poster插件、CURL、kibana5等。
1.ElasticSearch安装
ES服务只依赖于JDK,推荐使用JDK1.8+。本课程以在window环境下,ES 6.8.6版本为例,下载对应的ZIP文件
1.1.下载ElasticSearch
下载地址:Download Elasticsearch | Elastic
在window环境下,ES 6.8.6版本为例,下载对应的ZIP文件
1.2.安装与启动
解压即可,双击安装目录 bin/elasticsearch.bat即可启动
1.3.ElasticSearch测试
使用浏览器访问:http://localhost:9200
看到上图信息,恭喜你,你的ES集群已经启动并且正常运行.
1.4.ES内存配置
如果ES启动占用的内存比较大可以通过修改 jvm.options 文件来修改内存
Xms-1g
Xml-1g
2.Kibana5安装
2.1.下载Kibana5
下载地址:Download Kibana Free | Get Started Now | Elastic
2.2.安装与启动
解压即可安装 , 执行bin\kibana.bat 即可启动Kibana
2.3.Kinbana连接ES配置
解压并编辑config/kibana.yml,设置elasticsearch.url的值为已启动的ES
默认情况下,Kibana会链接本地的默认ES http://localhost:9200
,如果需要修改链接的ES服务器,通过修改安装目录下 config/kibana.yml,将配置项 #elasticsearch.url: "http://localhost:9200"
取消注释即可修改连接的ES服务器地址。
2.4.测试Kibana
浏览器访问 http://localhost:5601 Kibana默认地址
Kibana组件详细说明:https://www.cnblogs.com/hunttown/p/6768864.html
Discover:可视化查询分析器 Visualize:统计分析图表 Dashboard:自定义主面板(添加图表) Timelion:Timelion是一个kibana时间序列展示组件(暂时不用) Dev Tools :Console(同CURL/POSTER,操作ES代码工具,代码提示,很方便) Management:管理索引库(index)、已保存的搜索和可视化结果(save objects)、设置 kibana 服务器属性。
索引库CRUD
参考文章:ES索引的基本操作(CRUD)_es crud_三思呐三思的博客-CSDN博客
文档类型映射
参考文档:Elasticsearch(四)--一文弄懂ES的映射操作_es修改映射_雨~旋律的博客-CSDN博客
DSL查询
1.DSL查询:就是去看关键字在原始数据中匹不匹配,有可能匹配度非常低也会查询出来,使用DSL查询会计算结果的相关度评分,所以效率不如DSL过滤高
2.DSL过滤:就是去看关键字对应数据等不等与,没有第三种可能性,等于就查询出来,不等于就不要,DSL过滤不会计算相关度评分,并且使用DSL过滤查询出来的数据ES会做缓存,下次再查询直接从缓存中获取,所以使用DSL过滤效率对比DSL查询高
DSL查询+过滤
语法
GET /crm/user/_search
{
"query": {
"bool": { //booleanQuery 组合
"must": [{ //与(must) 或(should) 非(must not)
"match": { //match : 匹配,吧查询的内容分词后去查询
"username": "zs"
},
}],
"filter": {
"term": {
"name": "zs ls"
}
}
}
},
"from": 20,
"size": 10,
"_source": ["name", "age", "username"],
"sort": [{
"join_date": "desc"
}, {
"age": "asc"
}]
}
关键字查询:放到DSL查询(相关性排序)
等值匹配的条件:DSL过滤
查询方式
bool:组合
match:(分词)
term: (不分词)
prefix:前缀
range:范围
wildcard:通配符
SpringBoot整合ES
1、导入依赖
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
<version>6.8.6</version>
</dependency>
2、yaml配置
spring:
elasticsearch:
rest:
uris: http://localhost:9200 #默认可以不配
3.创建Doc对象
@Document(indexName="",type="_doc")
@Id :标记文档ID
@Field(type=FieldTypel.Text .. .. ... .)
/**
* 文档对象
*/
@Document(indexName = "order",type = "_doc")
@Data
public class OrderDoc {
@Id
private Long id;
//订单内容 Keyword 不分词
@Field(type = FieldType.Keyword)
private String title;
@Field(type = FieldType.Integer)
private Integer status;
//订单内容 text 分词 , 分词器k_smart
@Field(type = FieldType.Text,analyzer = "ik_smart",searchAnalyzer = "ik_smart")
private String contact;
}
4、创建repository
创建接口
继承:ElasticSearchRepository<文档对象,ID类型>
5、编写测试
增删改
package cn.ll;
import cn.ll.doc.OrderDoc;
import cn.ll.repository.OrderDocRespository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.Optional;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = App.class)
public class ESTest {
@Autowired
private ElasticsearchRestTemplate template;
@Autowired
private OrderDocRespository orderDocRespository;
/**
* 创建索引池的测试
* @throws Exception
*/
@Test
public void EsTest() throws Exception{
//创建索引库
boolean reslute = template.createIndex(OrderDoc.class);
System.out.println(reslute);
//添加索引类型
boolean reslute1 = template.putMapping(OrderDoc.class);
System.out.println(reslute1);
}
/**
* 测试添加
*/
@Test
public void EsAddTest() throws Exception{
OrderDoc orderDoc = new OrderDoc();
for (long i = 1; i <100 ; i++) {
orderDoc.setId(i);
orderDoc.setStatus(i%2==0?1:0);
orderDoc.setTitle("爱坤【"+i +"】号" );
orderDoc.setContact("对"+i+"号坤的收养订单");
orderDocRespository.save(orderDoc);
}
}
/**
* 查询
*/
@Test
public void findTest(){
Optional<OrderDoc> optional = orderDocRespository.findById(32L);
OrderDoc orderDoc = optional.get();
System.out.println(orderDoc);
}
/**
* 修改
*/
@Test
public void updateTest(){
Optional<OrderDoc> optional = orderDocRespository.findById(32L);
OrderDoc orderDoc = optional.get();
orderDoc.setTitle("萨拉黑哟");
orderDocRespository.save(orderDoc);
System.out.println(orderDoc);
}
}
查询
/**
* Dsl查询
*/
@Test
public void searchTest(){
//通过bulid构建查询对象
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
//分页
nativeSearchQueryBuilder.withPageable(PageRequest.of(0,10));
//排序
nativeSearchQueryBuilder.withSort(new FieldSortBuilder("id").order(SortOrder.ASC));
//查询条件query dsl查询的query
//bool 组合
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
//match查询 包含
boolQueryBuilder.must(new MatchQueryBuilder("contact","1号"));
//过滤
boolQueryBuilder.filter(new TermQueryBuilder("title","爱坤【1】号"))
.filter(new TermQueryBuilder("status",0));
nativeSearchQueryBuilder.withQuery(boolQueryBuilder);
SearchQuery searchQuery = nativeSearchQueryBuilder.build();
Page<OrderDoc> search = respository.search(searchQuery);
//总条数
long totalElements = search.getTotalElements();
System.out.println(totalElements);
//内容
List<OrderDoc> list = search.getContent();
list.forEach(System.out::println);
}