既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果词库中有这两个词:“狮子” 和 “虱子”,那么也就意味着,创建倒排索引时,通过上述自定义的 拼音分词器 ,就会把这两个词归为一个文档,因为他们在分词的时候,会分出共同的拼音 “shizi” 和 “sz”,这就导致他两的文档编号对应同一个词条,导致将来用户在搜索框里输入 “狮子” ,点击搜索之后,会同时搜索出 “狮子” 和 “虱子” ,这并不是我们想看到的.
解决方案
因此字段在创建倒排索引时因该使用 my_analyzer 分词器,但是字段在搜索时应该使用 ik_smart 分词器.
也就是说,用户输入中文的时候,就按中文去搜,用户输入拼音的时候,才按拼音去搜,即使出现上述情况,同时搜出这两个词,那你是按拼音搜,两个都是符合的,不存在歧义.
如下:
PUT /test
{
"settings": {
"analysis": {
"analyzer": {
"my_analyzer": {
"tokenizer": "ik_max_word",
"filter": "py"
}
},
"filter": {
"py": {
"type": "pinyin",
"keep_full_pinyin": false,
"keep_joined_full_pinyin": true,
"keep_original": true,
"limit_first_letter_length": 16,
"remove_duplicated_term": true,
"none_chinese_pinyin_tokenize": false
}
}
}
},
"mappings": {
"properties": {
"name": {
"type": "text",
"analyzer": "my_analyzer" //创建倒排索引使用 my_analyzer 分词器.
"search_analyzer": "ik_smart" //搜索时使用 ik_smart 分词器.
}
}
}
}
1.4、completion suggester 查询
1.4.1、基本概念和语法
es 中提供了 completion suggester 查询来实现自动补全功能. 这个查询会匹配用户输入内容开头的词条并返回.
为了提高补全查询的效率,对于文档中的字段类型有一些约束,如下:
- 参与补全查询的字段必须是 completion 类型.
- 参与 自动补全字段 的内容一般是多个词条形成的数组.
POST /test2/_search
{
"suggest": {
"title_suggest": { //自定义补全名
"text": "s", //用户在搜索框中输入的关键字
"completion": { // completion 是自动补全中的一种类型(最常用的)
"field": "补全时需要查询的字段名", //这里的字段名指向的是一个数组(字段必须是 completion 类型),就是要根据数组中的字段进行查询,然后自动补全
"skip_duplicates": true, //如果查询时有重复的词条,是否自动跳过(true 为跳过)
"size": 10 // 获取前 10 条结果.
}
}
}
}
1.4.2、示例一
这里我用一个示例来演示 completion suggester 的用法.
首先创建索引库(参与自动补全的字段类型必须是 completion).
PUT /test2
{
"mappings": {
"properties": {
"title": {
"type": "completion"
}
}
}
}
插入示例数据(字段内容一般是用来补全的多个词条形成的数组.)
POST test2/_doc
{
"title": ["Sony", "WH-1000XM3"]
}
POST test2/_doc
{
"title": ["SK-II", "PITERA"]
}
POST test2/_doc
{
"title": ["Nintendo", "switch"]
}
这里我们设置关键字为 “s”,来自动补全查询,如下:
POST /test2/_search
{
"suggest": {
"title_suggest": {
"text": "s",
"completion": {
"field": "title",
"skip_duplicates": true,
"size": 10
}
}
}
}
1.4.3、示例二
首先创建索引库,如下参与自动补全的字段为 suggestion(通过 copy title 得到).
PUT /test
{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "ik_smart",
"copy_to": "suggestion"
},
"suggestion": {
"type": "completion"
}
}
}
}
插入示例数据
POST test/_doc/1
{
"title": "今天天气真好"
}
POST test/_doc/2
{
"title": "我想出去玩"
}
POST test/_doc/3
{
"title": "我要去找小伙伴"
}
设置关键字为 “我”
POST /test/_search
{
"suggest": {
"title_suggest": {
"text": "我",
"completion": {
"field": "suggestion",
"skip_duplicates": true,
"size": 10
}
}
}
}
自动补全效果如下
1.4.4、示例(黑马旅游)
这里我们基于之前实现的黑马旅游案例来做栗子,实现步骤如下:
a)修改 hotel 索引库结构,设置自定义拼音分词器.
1.设置自定义分词器.
-
修改索引库的 name、all 字段(建立倒排索引使用 拼音分词器,搜索时使用 ik 分词器).
-
给索引库添加一个新字段 suggestion,类型为 completion 类型,使用自定义分词器.
PUT /hotel
{
"settings": {
"analysis": {
"analyzer": {
"text_anlyzer": {
"tokenizer": "ik_max_word",
"filter": "py"
},
"completion_analyzer": {
"tokenizer": "keyword",
"filter": "py"
}
},
"filter": {
"py": {
"type": "pinyin",
"keep_full_pinyin": false,
"keep_joined_full_pinyin": true,
"keep_original": true,
"limit_first_letter_length": 16,
"remove_duplicated_term": true,
"none_chinese_pinyin_tokenize": false
}
}
}
},
"mappings": {
"properties": {
"id":{
"type": "keyword"
},
"name":{
"type": "text",
"analyzer": "text_anlyzer",
"search_analyzer": "ik_smart",
"copy_to": "all"
},
"address":{
"type": "keyword",
"index": false
},
"price":{
"type": "integer"
},
"score":{
"type": "integer"
},
"brand":{
"type": "keyword",
"copy_to": "all"
},
"city":{
"type": "keyword"
},
"starName":{
"type": "keyword"
},
"business":{
"type": "keyword",
"copy_to": "all"
},
"location":{
"type": "geo_point"
},
"pic":{
"type": "keyword",
"index": false
},
"all":{
"type": "text",
"analyzer": "text_anlyzer",
"search_analyzer": "ik_smart"
},
"suggestion":{
"type": "completion",
"analyzer": "completion_analyzer"
}
}
}
}
b)给 HotelDoc 类添加 suggestion 字段
suggestion 字段(包含多个字段的数组,这里可以使用 List 表示),内容包含 brand、business.
Ps:name、all 是可以分词的,自动补全的 brand、business 是不可分词的,要使用不同的分词器组合.
@Data
@NoArgsConstructor
public class HotelDoc {
private Long id;
private String name;
private String address;
private Integer price;
private Integer score;
private String brand;
private String city;
private String starName;
private String business;
private String location;
private String pic;
private Object distance;
private Boolean isAD;
private List<String> suggestion;
public HotelDoc(Hotel hotel) {
this.id = hotel.getId();
this.name = hotel.getName();
this.address = hotel.getAddress();
this.price = hotel.getPrice();
this.score = hotel.getScore();
this.brand = hotel.getBrand();
this.city = hotel.getCity();
this.starName = hotel.getStarName();
this.business = hotel.getBusiness();
this.location = hotel.getLatitude() + ", " + hotel.getLongitude();
this.pic = hotel.getPic();
this.suggestion = new ArrayList<>();
suggestion.add(brand);
suggestion.add(business);
}
}
c)将数据重新导入到 hotel 索引库中
将 hotel 索引库删了,然后重建(a 中的 DSL). 通过单元测试将所有信息从数据库同步到 es 上.
@Test
public void testBulkDocument() throws IOException {
//1.获取酒店所有数据
List<Hotel> hotelList = hotelService.list();
//2.构造请求
BulkRequest request = new BulkRequest();
//3.准备参数
for(Hotel hotel : hotelList) {
//转化为文档(主要是地理位置)
HotelDoc hotelDoc = new HotelDoc(hotel);
String json = objectMapper.writeValueAsString(hotelDoc);
request.add(new IndexRequest("hotel").id(hotel.getId().toString()).source(json, XContentType.JSON));
}
//4.发送请求
client.bulk(request, RequestOptions.DEFAULT);
}
d)基于 JavaRestClient 编写 DSL
例如自动补全关键为 “h” 的内容.
@Test
public void testSuggestion() throws IOException {
//1.创建请求
SearchRequest request = new SearchRequest("hotel");
//2.准备参数
request.source().suggest(new SuggestBuilder().addSuggestion(
"testSuggestion",
SuggestBuilders
.completionSuggestion("suggestion")
.prefix("h")
.skipDuplicates(true)
.size(10)
));
//3.发送请求,接收响应
SearchResponse search = client.search(request, RequestOptions.DEFAULT);
//4.解析响应
handlerResponse(search);
}
这里可以对应着 DSL 语句来写.
对查询结果的处理如下:
//4.处理自动补全结果
Suggest suggest = response.getSuggest();
if(suggest != null) {
CompletionSuggestion suggestion = suggest.getSuggestion("testSuggestion");
for (CompletionSuggestion.Entry.Option option : suggestion.getOptions()) {
String text = option.getText().toString();
System.out.println(text);
}
}
这里可以对应着 DSL 语句来写.
运行结果如下:
1.5、黑马旅游案例
1.5.1、需求
首先搜索框的自动补全功能.
最终实现效果就类似于 百度的搜索框,比如当我们输入 “byby”,他就会立马自动补全出有关 byby 关键字的信息,如下图:
1.5.2、前端对接
在搜索框中输入,会触发以下请求. 这里前端就传入一个参数 key.
这里约定,返回的是一个 List,内容就是自动补全的所有信息.
1.5.3、实现 controller
这里使用 @RequestParam 接收前端传入的参数,然后调用 IhotelService 接口处理即可.
@RequestMapping("/suggestion")
public List<String> suggestion(@RequestParam("key") String prefix) {
return hotelService.suggestion(prefix);
}
1.5.4、创建接口并实现.
在 IhotelService 接口中创建 suggestion 方法.
public interface IHotelService extends IService<Hotel> {
PageResult search(RequestParams params);
![img](https://img-blog.csdnimg.cn/img_convert/8c98435af669d5266485878f1bd13a55.png)
![img](https://img-blog.csdnimg.cn/img_convert/f52c2ef335d6cb133255ece33b74e014.png)
![img](https://img-blog.csdnimg.cn/img_convert/1d89051c3196c4f5f0577a83b9a382b7.png)
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**
**[需要这份系统化资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618545628)**
elService.suggestion(prefix);
}
1.5.4、创建接口并实现.
在 IhotelService 接口中创建 suggestion 方法.
public interface IHotelService extends IService<Hotel> {
PageResult search(RequestParams params);
[外链图片转存中...(img-c45t6wCg-1715670755966)]
[外链图片转存中...(img-9gmOS5Ch-1715670755966)]
[外链图片转存中...(img-AwL46E3Z-1715670755967)]
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**
**[需要这份系统化资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618545628)**