文章目录
- Elasticserach
- WHAT
- WHY
- HOW
-
- 命令模式使用
- SpringBoot 集成Elcticsearch
Elasticserach
WHAT
Elasticsearch
,分布式全文搜索引擎。
它可以高效的 存储 和 检索 数据。
es 是使用 Java
语言开发的,并且基于 Lucene
,es 通过简单的RESTful API
来隐藏 Lucene的复杂性,从而使得全文搜索变得简单。
es 是 lucene 的封装,提供了RESTful API 的操作接口,开箱即用。
同类“竞品”
Solr
:是一个高性能,采用 Java 开发,基于Lucene的全文搜索服务器。它对外提供类似于web-service的API接口。
es 与 solr
- es基本是开箱即用,非常简单。而solr会有点复杂
- solr利用Zookeeper进行分布式管理,而elasticsearch自身带有分布式协调管理功能
- solr支持更多格式的数据,比如json xml csv。而es只支持json文件格式(够用)
- solr官方提供的功能更多,而elasticsearch更注重核心功能,高级功能由第三方插件提供
- solr查询快,但更新索引时慢,用于电商等查询多的应用
- es建立索引宽,即实时性查询快,用于facebook新浪等搜索
- solr较成熟,有一个更大,更成熟的用户、开发和贡献者社区,而elasticsearch相对开发维护者较少,更新太快,学习使用成本较高
WHY
使用数据库 来做搜索业务,不能很好的满足需求。
虽然某一程度上也可以视为数据库,但是它更主要的身份还是一个优秀的全文搜索引擎。它的出现解决了一部分传统关系型数据库和NoSQL非关系型数据库所没有办法高效完成的一些工作,比如高效的全文检索,结构化检索,甚至是数据分析。
响应时间
eg
:数据库在做模糊查询时,如LIKE
语句,它会遍历整张表,同时进行字符串匹配。
而 es
是基于 倒排索引 的 ,检索速度非常快。
分词
Elasticsearch
支持中文分词插件 IK
相关性
Elasticsearch
支持全文搜索和相关度评分。这样在返回结果就会根据分数由高到低排列。分数越高,意味着和查询语句越相关。
可视化界面
MySQL 的 Navicat
Elasticsearch 的 Kibana
HOW
Elasticsearch 中的概念:
Index
:索引(相当于数据库)
Document
:文档(一条条记录)
注意:高版本可以可能会舍弃 type
,创建的时候可以设置为默认(_doc)
IK分词器
默认的中文分词,是将每个字看成一个词,显然不符合需求,所以,需要安装中文分词器
ik
来解决问题。
IK 提供了两个分词算法:ik_smart
和 ik_max_word
- ik_smart:最少切分
- ik_max_word:最细粒度切分
eg:
GET _analyze
{
"analyzer": "ik_smart","text": "我是社会主义接班人"
}//输出
{
"tokens" : [{
"token" : "我","start_offset" : 0,"end_offset" : 1,"type" : "CN_CHAR","position" : 0},{
"token" : "是","start_offset" : 1,"end_offset" : 2,"type" : "CN_CHAR","position" : 1},{
"token" : "社会主义","start_offset" : 2,"end_offset" : 6,"type" : "CN_WORD","position" : 2},{
"token" : "接班人","start_offset" : 6,"end_offset" : 9,"type" : "CN_WORD","position" : 3}]
}
GET _analyze
{
"analyzer": "ik_max_word","text": "我是社会主义接班人"
}
//输出
{
"tokens" : [{
"token" : "我","start_offset" : 0,"end_offset" : 1,"type" : "CN_CHAR","position" : 0},{
"token" : "是","start_offset" : 1,"end_offset" : 2,"type" : "CN_CHAR","position" : 1},{
"token" : "社会主义","start_offset" : 2,"end_offset" : 6,"type" : "CN_WORD","position" : 2},{
"token" : "社会","start_offset" : 2,"end_offset" : 4,"type" : "CN_WORD","position" : 3},{
"token" : "主义","start_offset" : 4,"end_offset" : 6,"type" : "CN_WORD","position" : 4},{
"token" : "接班人","start_offset" : 6,"end_offset" : 9,"type" : "CN_WORD","position" : 5},{
"token" : "接班","start_offset" : 6,"end_offset" : 8,"type" : "CN_WORD","position" : 6},{
"token" : "人","start_offset" : 8,"end_offset" : 9,"type" : "CN_CHAR","position" : 7}]
}
命令模式使用
method | url地址 | 描述 |
---|---|---|
PUT | localhost:9200/索引名称/类型名称/文档id | 创建文档(指定文档id) |
POST | localhost:9200/索引名称/类型名称 | 创建文档(随机文档id) |
POST | localhost:9200/索引名称/类型名称/文档id/_update | 修改文档 |
DELETE | localhost:9200/索引名称/类型名称/文档id | 删除文档 |
GET | localhost:9200/索引名称/类型名称/文档id | 通过文档id查询文档 |
POST | localhost:9200/索引名称/类型名称/_search | 查询所有的数据 |
SpringBoot 集成Elcticsearch
配置类:
/*** SpringBoot与Elasticsearch集成* 之后,用这个client对象就可以了*/
@Configuration
public class ElasticsearchClientConfig {@Beanpublic RestHighLevelClient restHighLevelClient(){RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(new HttpHost("localhost", 9200, "http")));return client;}
}
搜索test
@Autowiredpublic RestHighLevelClient restHighLevelClient;@Testvoid testSearch() throws IOException {
SearchRequest searchRequest = new SearchRequest();//构建搜索条件SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();//构建高亮// searchSourceBuilder.highlighter();//查询条件,可以使用 QueryBuilders 工具来实现 精确查询 QueryBuilders.termQuery()TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name", "damin");//匹配全部//MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();searchSourceBuilder.query(termQueryBuilder);//设置分页//不设置 SearchSourceBuilder 也有默认值//searchSourceBuilder.from();//searchSourceBuilder.size();//设置搜索时间,(时间不要超过多少)searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));//放到请求中searchRequest.source(searchSourceBuilder);//执行请求SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);// searchResponse.getHits() //所有的结果都封装在 SearchHits -> getHits//遍历for (SearchHit documentFields : searchResponse.getHits().getHits()) {
System.out.println(documentFields.getSourceAsMap());}}
爬取京东商品页面实例部分代码
视频:遇见狂神说
//普通搜索Service@Autowiredpublic RestHighLevelClient restHighLevelClient;//获取数据实现搜索功能public List<Map<String,Object>> searchPage(String keyword,int pageNo,int pageSize) throws IOException {
if (pageNo <= 1) {
pageNo = 1;}//搜索条件 eg: goodsSearchRequest searchRequest = new SearchRequest("索引");SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();//分页sourceBuilder.from(pageNo);sourceBuilder.size(pageSize);//精准匹配TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", keyword);sourceBuilder.query(termQueryBuilder);sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));//执行搜索searchRequest.source(sourceBuilder);//通过客户端进行查询SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);//解析结果ArrayList<Map<String,Object>> list = new ArrayList<>();for (SearchHit documentFields : searchResponse.getHits().getHits()) {
//把 documentFields结果 变成map 返回list.add(documentFields.getSourceAsMap());}return list;}
//高亮显示public List<Map<String,Object>> searchPageHighlightBuilder(String keyword,int pageNo,int pageSize) throws IOException {
if (pageNo <= 1) {
pageNo = 1;}//搜索条件 eg: goodsSearchRequest searchRequest = new SearchRequest("索引");SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();//分页sourceBuilder.from(pageNo);sourceBuilder.size(pageSize);//精准匹配TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", keyword);sourceBuilder.query(termQueryBuilder);sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));//高亮HighlightBuilder highlightBuilder = new HighlightBuilder();highlightBuilder.field("title");highlightBuilder.requireFieldMatch(false); //多个高亮显示highlightBuilder.preTags("<span style='color:red'>");//前缀标签highlightBuilder.postTags("</span>"); //后缀标签//标签,vue解析 :v-html=""sourceBuilder.highlighter(highlightBuilder);//执行搜索searchRequest.source(sourceBuilder);//通过客户端进行查询SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);//解析结果ArrayList<Map<String,Object>> list = new ArrayList<>();for (SearchHit documentFields : searchResponse.getHits().getHits()) {
//获取高亮字段Map<String, HighlightField> highlightFields = documentFields.getHighlightFields();HighlightField title = highlightFields.get("title");//原来的结果 把原来没有高亮的字段 => 替换为有高亮的字段Map<String, Object> sourceAsMap = documentFields.getSourceAsMap();//解析高亮字段if (title != null) {
Text[] fragments = title.fragments();String n_title = "";for (Text text : fragments) {
n_title += text;}sourceAsMap.put("title",n_title);}list.add(sourceAsMap);}return list;}
Controller
@GetMapping("/search/{keyword}/{pageNo}/{pageSize}")public List<Map<String,Object>> search(@PathVariable("keyword") String keyword,@PathVariable("pageNo") int pageNo,@PathVariable("pageSize") int pageSize) throws IOException {
//一些基本业务,比如没有传到值if (pageNo == 0){
}return contentService.searchPage(keyword,pageNo,pageSize);}