翼度科技»论坛 编程开发 .net 查看内容

Elasticsearch 系列(四)- DSL实现自动补全查询

7

主题

7

帖子

21

积分

新手上路

Rank: 1

积分
21
本章将和大家分享如何通过 Elasticsearch 实现自动补全查询功能。
一、自动补全-安装拼音分词器

1、自动补全需求说明

当用户在搜索框输入字符时,我们应该提示出与该字符有关的搜索项,如图:

2、使用拼音分词

要实现根据字母做补全,就必须对文档按照拼音分词。在 GitHub 上恰好有 Elasticsearch 的拼音分词插件地址:https://github.com/infinilabs/analysis-pinyin
安装方式与IK分词器一样,分三步:
1)解压
2)上传到 Elasticsearch 的 plugins 目录下
3)重启 Elasticsearch
4)测试 
首先从 GitHub 上下载 Elasticsearch 的拼音分词插件,如下所示:

下载完成后,将其解压出来,然后将解压后的文件夹名称重命名为 “py” ,最后把它复制到 Elasticsearch 的 plugins 目录下,如下所示:


安装完成后,需要重启一下 Elasticsearch ,如下所示:

可以发现拼音分词器插件安装成功了。 
最后我们来测试一下:
  1. # 测试拼音分词
  2. POST /_analyze
  3. {
  4.   "text": "如家酒店还不错",
  5.   "analyzer": "pinyin"
  6. }
复制代码

运行结果如下:
  1. {
  2.   "tokens" : [
  3.     {
  4.       "token" : "ru",
  5.       "start_offset" : 0,
  6.       "end_offset" : 0,
  7.       "type" : "word",
  8.       "position" : 0
  9.     },
  10.     {
  11.       "token" : "rjjdhbc",
  12.       "start_offset" : 0,
  13.       "end_offset" : 0,
  14.       "type" : "word",
  15.       "position" : 0
  16.     },
  17.     {
  18.       "token" : "jia",
  19.       "start_offset" : 0,
  20.       "end_offset" : 0,
  21.       "type" : "word",
  22.       "position" : 1
  23.     },
  24.     {
  25.       "token" : "jiu",
  26.       "start_offset" : 0,
  27.       "end_offset" : 0,
  28.       "type" : "word",
  29.       "position" : 2
  30.     },
  31.     {
  32.       "token" : "dian",
  33.       "start_offset" : 0,
  34.       "end_offset" : 0,
  35.       "type" : "word",
  36.       "position" : 3
  37.     },
  38.     {
  39.       "token" : "hai",
  40.       "start_offset" : 0,
  41.       "end_offset" : 0,
  42.       "type" : "word",
  43.       "position" : 4
  44.     },
  45.     {
  46.       "token" : "bu",
  47.       "start_offset" : 0,
  48.       "end_offset" : 0,
  49.       "type" : "word",
  50.       "position" : 5
  51.     },
  52.     {
  53.       "token" : "cuo",
  54.       "start_offset" : 0,
  55.       "end_offset" : 0,
  56.       "type" : "word",
  57.       "position" : 6
  58.     }
  59.   ]
  60. }
复制代码
从该查询结果可以看出拼音分词器存在的一些问题
1)第一个问题是拼音分词器它不会分词。
2)第二个问题是它把一句话里面的每一个字都形成了拼音,这对我们来说不仅没什么用,而且还会占用空间。
3)第三个问题是拼音分词结果中没有汉字只剩下了拼音,而实际上我们用拼音搜索的情况是占少数的,大多数情况下其实我们是想通过中文去搜索的,所以说有拼音是锦上添花,但是不能把汉字给扔了,汉字也得保留。
这是我们拼音分词器目前所面临的几个问题,因此我们就必须得对拼音分词器做一些配置或者叫做自定义了,那么怎么样才能实现自定义分词器呢?
二、自动补全-自定义分词器

Elasticsearch中分词器(analyzer)的组成包含三部分:

  • character filters:在tokenizer之前对文本进行处理。例如:删除字符、替换字符。
  • tokenizer:将文本按照一定的规则切割成词条(term)。例如:keyword 就是不分词、还有ik_smart 。
  • tokenizer filter:对tokenizer输出的词条做进一步的处理。例如:大小写转换、同义词处理、拼音处理等。

我们可以在创建索引库时,通过settings来配置自定义的analyzer(分词器):
  1. PUT /test
  2. {
  3.   "settings": {
  4.     "analysis": {
  5.       "analyzer": { //自定义分词器
  6.         "my_analyzer": { //自定义分词器的名称
  7.           "tokenizer": "ik_max_word",
  8.           "filter": "pinyin"
  9.         }
  10.       }
  11.     }
  12.   }
  13. }
复制代码
上面这个只是解决了拼音分词器分词的问题,因此还需要对拼音分词器做进一步的定制,如下所示:
  1. # 自定义拼音分词器
  2. PUT /test
  3. {
  4.   "settings": {
  5.     "analysis": {
  6.       "analyzer": { //自定义分词器
  7.         "my_analyzer": { //自定义分词器名称
  8.           "tokenizer": "ik_max_word",
  9.           "filter": "py" //过滤器名称,可以是自定义的过滤器
  10.         }
  11.       },
  12.       "filter": { //自定义tokenizer filter
  13.         "py": { //自定义过滤器的名称,可随意取
  14.           "type": "pinyin", //过滤器类型,这里是pinyin
  15.           "keep_full_pinyin": false, //修改可选参数,具体可参考拼音分词器GitHub官网
  16.           "keep_joined_full_pinyin": true,
  17.           "keep_original": true,
  18.           "limit_first_letter_length": 16,
  19.           "remove_duplicated_term": true,
  20.           "none_chinese_pinyin_tokenize": false
  21.         }
  22.       }
  23.     }
  24.   },
  25.   "mappings": {
  26.     "properties": {
  27.       "name": {
  28.         "type": "text",
  29.         "analyzer": "my_analyzer" //使用自定义分词器
  30.       }
  31.     }
  32.   }
  33. }
复制代码
拼音分词器更多可选参数可参考GitHub官网:https://github.com/infinilabs/analysis-pinyin
test索引库创建完成后,下面我们来测试下:
  1. # 测试自定义分词器
  2. POST /test/_analyze
  3. {
  4.   "text": [
  5.     "如家酒店还不错"
  6.   ],
  7.   "analyzer": "my_analyzer"
  8. }
复制代码
注意:在test索引库中自定义的分词器也只能在test索引库中使用。
运行结果如下:
  1. {
  2.   "tokens" : [
  3.     {
  4.       "token" : "如家",
  5.       "start_offset" : 0,
  6.       "end_offset" : 2,
  7.       "type" : "CN_WORD",
  8.       "position" : 0
  9.     },
  10.     {
  11.       "token" : "rujia",
  12.       "start_offset" : 0,
  13.       "end_offset" : 2,
  14.       "type" : "CN_WORD",
  15.       "position" : 0
  16.     },
  17.     {
  18.       "token" : "rj",
  19.       "start_offset" : 0,
  20.       "end_offset" : 2,
  21.       "type" : "CN_WORD",
  22.       "position" : 0
  23.     },
  24.     {
  25.       "token" : "酒店",
  26.       "start_offset" : 2,
  27.       "end_offset" : 4,
  28.       "type" : "CN_WORD",
  29.       "position" : 1
  30.     },
  31.     {
  32.       "token" : "jiudian",
  33.       "start_offset" : 2,
  34.       "end_offset" : 4,
  35.       "type" : "CN_WORD",
  36.       "position" : 1
  37.     },
  38.     {
  39.       "token" : "jd",
  40.       "start_offset" : 2,
  41.       "end_offset" : 4,
  42.       "type" : "CN_WORD",
  43.       "position" : 1
  44.     },
  45.     {
  46.       "token" : "还不",
  47.       "start_offset" : 4,
  48.       "end_offset" : 6,
  49.       "type" : "CN_WORD",
  50.       "position" : 2
  51.     },
  52.     {
  53.       "token" : "haibu",
  54.       "start_offset" : 4,
  55.       "end_offset" : 6,
  56.       "type" : "CN_WORD",
  57.       "position" : 2
  58.     },
  59.     {
  60.       "token" : "hb",
  61.       "start_offset" : 4,
  62.       "end_offset" : 6,
  63.       "type" : "CN_WORD",
  64.       "position" : 2
  65.     },
  66.     {
  67.       "token" : "不错",
  68.       "start_offset" : 5,
  69.       "end_offset" : 7,
  70.       "type" : "CN_WORD",
  71.       "position" : 3
  72.     },
  73.     {
  74.       "token" : "bucuo",
  75.       "start_offset" : 5,
  76.       "end_offset" : 7,
  77.       "type" : "CN_WORD",
  78.       "position" : 3
  79.     },
  80.     {
  81.       "token" : "bc",
  82.       "start_offset" : 5,
  83.       "end_offset" : 7,
  84.       "type" : "CN_WORD",
  85.       "position" : 3
  86.     }
  87.   ]
  88. }
复制代码
可以看出,搜索结果中既有汉字、又有拼音、还有分词,这完全符合我们的预期。
但是需要特别注意的是:拼音分词器适合在创建倒排索引的时候使用,不适合在搜索的时候使用。下面我们通过一个例子来说明:
往test索引库中加入2条测试数据,如下所示:
  1. POST /test/_doc/1
  2. {
  3.   "id": 1,
  4.   "name": "狮子"
  5. }
  6. POST /test/_doc/2
  7. {
  8.   "id": 2,
  9.   "name": "虱子"
  10. }
复制代码
接着我们搜索“掉入狮子笼咋办”,如下所示:
  1. GET /test/_search
  2. {
  3.   "query": {
  4.     "match": {
  5.       "name": "掉入狮子笼咋办"
  6.     }
  7.   }
  8. }
复制代码
运行结果如下:

可以发现,其实我们是想找“狮子”,但是它把同音字“虱子” 也搜索出来了。下面我们通过一张图来了解一下这个过程,如下所示:

由此可见,拼音分词器适合在创建倒排索引的时候使用,但不能在搜索的时候使用。
正确的做法是:字段在创建倒排索引时应该用my_analyzer分词器,而字段在搜索时应该使用ik_smart分词器。如下所示:
  1. # 自定义拼音分词器
  2. PUT /test
  3. {
  4.   "settings": {
  5.     "analysis": {
  6.       "analyzer": { //自定义分词器
  7.         "my_analyzer": { //自定义分词器名称
  8.           "tokenizer": "ik_max_word",
  9.           "filter": "py" //过滤器名称,可以是自定义的过滤器
  10.         }
  11.       },
  12.       "filter": { //自定义tokenizer filter
  13.         "py": { //自定义过滤器的名称,可随意取
  14.           "type": "pinyin", //过滤器类型,这里是pinyin
  15.           "keep_full_pinyin": false, //修改可选参数,具体可参考拼音分词器GitHub官网
  16.           "keep_joined_full_pinyin": true,
  17.           "keep_original": true,
  18.           "limit_first_letter_length": 16,
  19.           "remove_duplicated_term": true,
  20.           "none_chinese_pinyin_tokenize": false
  21.         }
  22.       }
  23.     }
  24.   },
  25.   "mappings": {
  26.     "properties": {
  27.       "name": {
  28.         "type": "text",
  29.         "analyzer": "my_analyzer", //创建倒排索引时使用自定义分词器
  30.         "search_analyzer": "ik_smart" //搜索时应该使用ik_smart分词器
  31.       }
  32.     }
  33.   }
  34. }
复制代码
总结:
1、如何使用拼音分词器?

  • 下载 pinyin 分词器
  • 解压并放到 Elasticsearch 的 plugins 目录
  • 重启即可
2、如何自定义分词器?

  • 创建索引库时,在 settings 中配置,可以包含三部分
  • character filter
  • tokenizer
  • filter
3、拼音分词器注意事项?

  • 为了避免搜索到同音字,搜索时不要使用拼音分词器。
三、自动补全-DSL实现自动补全查询

Elasticsearch 提供了 Completion Suggester 查询来实现自动补全功能。官方文档地址:https://www.elastic.co/guide/en/elasticsearch/reference/7.6/search-suggesters.html#completion-suggester
这个查询会匹配以用户输入内容开头的词条并返回。为了提高补全查询的效率,对于文档中字段的类型有一些约束:

  • 参与补全查询的字段必须是completion类型。
  • 字段的内容一般是用来补全的多个词条形成的数组。
  1. # 创建索引库
  2. PUT test
  3. {
  4.   "mappings": {
  5.     "properties": {
  6.       "title": {
  7.         "type": "completion"
  8.       }
  9.     }
  10.   }
  11. }
复制代码
  1. # 示例数据
  2. POST test/_doc
  3. {
  4.   "title": [
  5.     "Sony",
  6.     "WH-1000XM3"
  7.   ]
  8. }
  9. POST test/_doc
  10. {
  11.   "title": [
  12.     "SK-II",
  13.     "PITERA"
  14.   ]
  15. }
  16. POST test/_doc
  17. {
  18.   "title": [
  19.     "Nintendo",
  20.     "switch"
  21.   ]
  22. }
复制代码
查询语法如下:
  1. # 自动补全查询
  2. GET /test/_search
  3. {
  4.   "suggest": {
  5.     "title_suggest": { //自动补全查询的名称(自定义的名称)
  6.       "text": "s",  //搜索关键字
  7.       "completion": {
  8.         "field": "title", //自动补全查询的字段
  9.         "skip_duplicates": true, //跳过重复的
  10.         "size": 10 //获取前10条结果
  11.       }
  12.     }
  13.   }
  14. }
复制代码
查询结果如下:
  1. {
  2.   "took" : 0,
  3.   "timed_out" : false,
  4.   "_shards" : {
  5.     "total" : 1,
  6.     "successful" : 1,
  7.     "skipped" : 0,
  8.     "failed" : 0
  9.   },
  10.   "hits" : {
  11.     "total" : {
  12.       "value" : 0,
  13.       "relation" : "eq"
  14.     },
  15.     "max_score" : null,
  16.     "hits" : [ ]
  17.   },
  18.   "suggest" : {
  19.     "title_suggest" : [
  20.       {
  21.         "text" : "s",
  22.         "offset" : 0,
  23.         "length" : 1,
  24.         "options" : [
  25.           {
  26.             "text" : "SK-II",
  27.             "_index" : "test",
  28.             "_type" : "_doc",
  29.             "_id" : "2CJaPY4Bne6OHhy3cho1",
  30.             "_score" : 1.0,
  31.             "_source" : {
  32.               "title" : [
  33.                 "SK-II",
  34.                 "PITERA"
  35.               ]
  36.             }
  37.           },
  38.           {
  39.             "text" : "Sony",
  40.             "_index" : "test",
  41.             "_type" : "_doc",
  42.             "_id" : "1yJaPY4Bne6OHhy3WBoZ",
  43.             "_score" : 1.0,
  44.             "_source" : {
  45.               "title" : [
  46.                 "Sony",
  47.                 "WH-1000XM3"
  48.               ]
  49.             }
  50.           },
  51.           {
  52.             "text" : "switch",
  53.             "_index" : "test",
  54.             "_type" : "_doc",
  55.             "_id" : "2SJaPY4Bne6OHhy3fBod",
  56.             "_score" : 1.0,
  57.             "_source" : {
  58.               "title" : [
  59.                 "Nintendo",
  60.                 "switch"
  61.               ]
  62.             }
  63.           }
  64.         ]
  65.       }
  66.     ]
  67.   }
  68. }
复制代码
自动补全对字段的要求:

  • 类型是completion类型
  • 字段值是多词条的数组
四、自动补全-酒店数据自动补全(案例)

案例:实现hotel索引库的自动补全、拼音搜索功能
实现思路如下:
1、修改hotel索引库结构,设置自定义拼音分词器。
2、修改索引库的name、all字段,使用自定义分词器。
3、索引库添加一个新字段suggestion,类型为completion类型,使用自定义的分词器。
4、给HotelDoc类添加suggestion字段,内容包含brand、business 。
5、重新导入数据到hotel索引库
注意:name、all是可分词的,自动补全的brand、business是不可分词的,要使用不同的分词器组合。
  1. # 创建酒店数据索引库
  2. PUT /hotel
  3. {
  4.   "settings": {
  5.     "analysis": {
  6.       "analyzer": {
  7.         "text_anlyzer": { //自定义分词器,在创建倒排索引时使用
  8.           "tokenizer": "ik_max_word",
  9.           "filter": "py" //自定义过滤器py
  10.         },
  11.         "completion_analyzer": { //自定义分词器,用于实现自动补全
  12.           "tokenizer": "keyword", //不分词
  13.           "filter": "py" //自定义过滤器py
  14.         }
  15.       },
  16.       "filter": { //自定义tokenizer filter
  17.         "py": { //自定义过滤器的名称,可随意取
  18.           "type": "pinyin",
  19.           "keep_full_pinyin": false, //可选参数配置,具体可参考拼音分词器Github官网
  20.           "keep_joined_full_pinyin": true,
  21.           "keep_original": true,
  22.           "limit_first_letter_length": 16,
  23.           "remove_duplicated_term": true,
  24.           "none_chinese_pinyin_tokenize": false
  25.         }
  26.       }
  27.     }
  28.   },
  29.   "mappings": {
  30.     "properties": {
  31.       "id": {
  32.         "type": "keyword" //不分词
  33.       },
  34.       "name": {
  35.         "type": "text", //分词
  36.         "analyzer": "text_anlyzer", //在创建倒排索引时使用自定义分词器text_anlyzer
  37.         "search_analyzer": "ik_smart", //在搜索时使用ik_smart
  38.         "copy_to": "all" //拷贝到all字段
  39.       },
  40.       "address": {
  41.         "type": "keyword",
  42.         "index": false //不创建倒排索引,不参与搜索
  43.       },
  44.       "price": {
  45.         "type": "integer"
  46.       },
  47.       "score": {
  48.         "type": "integer"
  49.       },
  50.       "brand": {
  51.         "type": "keyword",
  52.         "copy_to": "all" //拷贝到all字段
  53.       },
  54.       "city": {
  55.         "type": "keyword"
  56.       },
  57.       "starName": {
  58.         "type": "keyword"
  59.       },
  60.       "business": {
  61.         "type": "keyword",
  62.         "copy_to": "all" //拷贝到all字段
  63.       },
  64.       "location": {
  65.         "type": "geo_point" //geo_point地理坐标类型
  66.       },
  67.       "pic": {
  68.         "type": "keyword",
  69.         "index": false //不创建倒排索引,不参与搜索
  70.       },
  71.       "all": { //该字段主要用于搜索,没有实际意义,且在搜索结果的原始文档中你是看不到该字段的
  72.         "type": "text",
  73.         "analyzer": "text_anlyzer", //在创建倒排索引时使用自定义分词器text_anlyzer
  74.         "search_analyzer": "ik_smart" //在搜索时使用ik_smart
  75.       },
  76.       "suggestion": { //自动补全搜索字段
  77.         "type": "completion", //completion为自动补全类型
  78.         "analyzer": "completion_analyzer" //自动补全使用自定义分词器completion_analyzer
  79.       }
  80.     }
  81.   }
  82. }
复制代码
由于hotel索引库发生了变更,因此我们需要重新初始化一下ES的数据,此处我采用了.net代码实现了将酒店数据批量导入到ES中,关键代码如下所示:
Hotel类(酒店数据):
  1. using SqlSugar;
  2. namespace Demo.Domain.Entities
  3. {
  4.     /// <summary>
  5.     /// 酒店数据
  6.     /// </summary>
  7.     [SugarTable("tb_hotel")] //指定数据库表名
  8.     public class Hotel
  9.     {
  10.         /// <summary>
  11.         /// 酒店id
  12.         /// </summary>
  13.         [SugarColumn(IsPrimaryKey = true)] //数据库是主键需要加上IsPrimaryKey
  14.         public long id { get; set; }
  15.         /// <summary>
  16.         /// 酒店名称
  17.         /// </summary>
  18.         public string name { get; set; }
  19.         /// <summary>
  20.         /// 酒店地址
  21.         /// </summary>
  22.         public string address { get; set; }
  23.         /// <summary>
  24.         /// 酒店价格
  25.         /// </summary>
  26.         public int price { get; set; }
  27.         /// <summary>
  28.         /// 酒店评分
  29.         /// </summary>
  30.         public int score { get; set; }
  31.         /// <summary>
  32.         /// 酒店品牌
  33.         /// </summary>
  34.         public string brand { get; set; }
  35.         /// <summary>
  36.         /// 所在城市
  37.         /// </summary>
  38.         public string city { get; set; }
  39.         /// <summary>
  40.         /// 酒店星级
  41.         /// </summary>
  42.         [SugarColumn(ColumnName = "star_name")] //指定数据库表字段
  43.         public string starName { get; set; }
  44.         /// <summary>
  45.         /// 商圈
  46.         /// </summary>
  47.         public string business { get; set; }
  48.         /// <summary>
  49.         /// 纬度
  50.         /// </summary>
  51.         public string latitude { get; set; }
  52.         /// <summary>
  53.         /// 经度
  54.         /// </summary>
  55.         public string longitude { get; set; }
  56.         /// <summary>
  57.         /// 酒店图片
  58.         /// </summary>
  59.         public string pic { get; set; }
  60.     }
  61. }
复制代码
View CodeHotelDoc类(酒店数据对应的ES文档):
  1. using System;
  2. namespace Demo.Domain.Docs
  3. {
  4.     /// <summary>
  5.     /// 酒店数据对应的ES文档
  6.     /// </summary>
  7.     public class HotelDoc
  8.     {
  9.         /// <summary>
  10.         /// 酒店id
  11.         /// </summary>
  12.         public long id { get; set; }
  13.         /// <summary>
  14.         /// 酒店名称
  15.         /// </summary>
  16.         public string name { get; set; }
  17.         /// <summary>
  18.         /// 酒店地址
  19.         /// </summary>
  20.         public string address { get; set; }
  21.         /// <summary>
  22.         /// 酒店价格
  23.         /// </summary>
  24.         public int price { get; set; }
  25.         /// <summary>
  26.         /// 酒店评分
  27.         /// </summary>
  28.         public int score { get; set; }
  29.         /// <summary>
  30.         /// 酒店品牌
  31.         /// </summary>
  32.         public string brand { get; set; }
  33.         /// <summary>
  34.         /// 所在城市
  35.         /// </summary>
  36.         public string city { get; set; }
  37.         /// <summary>
  38.         /// 酒店星级
  39.         /// </summary>
  40.         public string starName { get; set; }
  41.         /// <summary>
  42.         /// 商圈
  43.         /// </summary>
  44.         public string business { get; set; }
  45.         /// <summary>
  46.         /// 纬度
  47.         /// </summary>
  48.         //public string latitude { get; set; }
  49.         /// <summary>
  50.         /// 经度
  51.         /// </summary>
  52.         //public string longitude { get; set; }
  53.         /// <summary>
  54.         /// 地理坐标字段(将经度和纬度字段合并成一个地理坐标字段)
  55.         /// 将经度和纬度的字段值用英文逗号拼在一起,例如:"40.048969, 116.619566"
  56.         /// </summary>
  57.         public string location { get; set; }
  58.         /// <summary>
  59.         /// 酒店图片
  60.         /// </summary>
  61.         public string pic { get; set; }
  62.         /// <summary>
  63.         /// 自动补全搜索字段
  64.         /// </summary>
  65.         public List<string> suggestion { get; set; }
  66.     }
  67. }
复制代码
View CodeHotel类 和 HotelDoc类 二者的映射关系:
  1. using AutoMapper;
  2. using Demo.Domain.Docs;
  3. using Demo.Domain.Entities;
  4. namespace Demo.Domain.AutoMapperConfigs
  5. {
  6.     public class MyProfile : Profile
  7.     {
  8.         public MyProfile()
  9.         {
  10.             // 配置 mapping 规则
  11.             CreateMap<Hotel, HotelDoc>()
  12.                 .AfterMap((tbl, doc) =>
  13.                 {
  14.                     #region 地理坐标字段处理
  15.                     if (!string.IsNullOrEmpty(tbl.latitude) && !string.IsNullOrEmpty(tbl.longitude))
  16.                     {
  17.                         //将经度和纬度的字段值用英文逗号拼在一起,例如:"40.048969, 116.619566"
  18.                         doc.location = string.Format(@"{0}, {1}", tbl.latitude, tbl.longitude);
  19.                     }
  20.                     #endregion
  21.                     #region 自动补全搜索字段处理
  22.                     var suggestionList = new List<string>();
  23.                     if (!string.IsNullOrEmpty(tbl.brand))
  24.                     {
  25.                         //品牌
  26.                         suggestionList.Add(tbl.brand);
  27.                     }
  28.                     if (!string.IsNullOrEmpty(tbl.business))
  29.                     {
  30.                         //商圈
  31.                         if (tbl.business.Contains("/"))
  32.                         {
  33.                             suggestionList.AddRange(tbl.business.Split('/'));
  34.                         }
  35.                         else
  36.                         {
  37.                             suggestionList.Add(tbl.business);
  38.                         }
  39.                     }
  40.                     doc.suggestion = suggestionList;
  41.                     #endregion
  42.                 });
  43.         }
  44.     }
  45. }
复制代码
View Code将酒店数据批量插入到ES中:
  1. using Microsoft.AspNetCore.Mvc;
  2. using AutoMapper;
  3. using Demo.Domain.Docs;
  4. using Demo.Domain.Entities;
  5. using Demo.Infrastructure.Repositories;
  6. using TianYaSharpCore.Elasticsearch;
  7. namespace Demo.MVC.Controllers
  8. {
  9.     public class HomeController : Controller
  10.     {
  11.         private readonly HotelRepository _hotelRepository;
  12.         private readonly IElasticClientProvider _elasticClientProvider;
  13.         private readonly IMapper _mapper;
  14.         public HomeController(HotelRepository hotelRepository, IElasticClientProvider elasticClientProvider, IMapper mapper)
  15.         {
  16.             _hotelRepository = hotelRepository;
  17.             _elasticClientProvider = elasticClientProvider;
  18.             _mapper = mapper;
  19.         }
  20.         public async Task<IActionResult> Index()
  21.         {
  22.             //从数据库中查出所有的酒店数据
  23.             var hotelList = await _hotelRepository._sqlSugarClient.Queryable<Hotel>().ToListAsync();
  24.             //实体转换
  25.             var hotelDocList = _mapper.Map<List<HotelDoc>>(hotelList);
  26.             //使用Nest将酒店数据批量插入到ES中
  27.             var asyncBulkIndexResponse = await _elasticClientProvider.ElasticLinqClient.BulkAsync(bulk => bulk
  28.                 .Index("hotel")
  29.                 .IndexMany(hotelDocList)
  30.             );
  31.             return View();
  32.         }
  33.     }
  34. }
复制代码
View CodeES数据初始化完成后,最后我们再去试一下酒店数据的自动补全查询,如下所示:
  1. # 自动补全查询
  2. GET /hotel/_search
  3. {
  4.   "suggest": {
  5.     "mySuggestion": {
  6.       "text": "sd",
  7.       "completion": {
  8.         "field": "suggestion",
  9.         "skip_duplicates": true,
  10.         "size": 10
  11.       }
  12.     }
  13.   }
  14. }
复制代码
运行结果如下所示:
  1. {
  2.   "took" : 1,
  3.   "timed_out" : false,
  4.   "_shards" : {
  5.     "total" : 1,
  6.     "successful" : 1,
  7.     "skipped" : 0,
  8.     "failed" : 0
  9.   },
  10.   "hits" : {
  11.     "total" : {
  12.       "value" : 0,
  13.       "relation" : "eq"
  14.     },
  15.     "max_score" : null,
  16.     "hits" : [ ]
  17.   },
  18.   "suggest" : {
  19.     "mySuggestion" : [
  20.       {
  21.         "text" : "sd",
  22.         "offset" : 0,
  23.         "length" : 2,
  24.         "options" : [
  25.           {
  26.             "text" : "上地产业园",
  27.             "_index" : "hotel",
  28.             "_type" : "_doc",
  29.             "_id" : "2359697",
  30.             "_score" : 1.0,
  31.             "_source" : {
  32.               "id" : 2359697,
  33.               "name" : "如家酒店(北京上地安宁庄东路店)",
  34.               "address" : "清河小营安宁庄东路18号20号楼",
  35.               "price" : 420,
  36.               "score" : 46,
  37.               "brand" : "如家",
  38.               "city" : "北京",
  39.               "starName" : "二钻",
  40.               "business" : "上地产业园/西三旗",
  41.               "location" : "40.041322, 116.333316",
  42.               "pic" : "https://m.tuniucdn.com/fb3/s1/2n9c/2wj2f8mo9WZQCmzm51cwkZ9zvyp8_w200_h200_c1_t0.jpg",
  43.               "suggestion" : [
  44.                 "如家",
  45.                 "上地产业园",
  46.                 "西三旗"
  47.               ]
  48.             }
  49.           },
  50.           {
  51.             "text" : "首都机场",
  52.             "_index" : "hotel",
  53.             "_type" : "_doc",
  54.             "_id" : "395702",
  55.             "_score" : 1.0,
  56.             "_source" : {
  57.               "id" : 395702,
  58.               "name" : "北京首都机场希尔顿酒店",
  59.               "address" : "首都机场3号航站楼三经路1号",
  60.               "price" : 222,
  61.               "score" : 46,
  62.               "brand" : "希尔顿",
  63.               "city" : "北京",
  64.               "starName" : "五钻",
  65.               "business" : "首都机场/新国展地区",
  66.               "location" : "40.048969, 116.619566",
  67.               "pic" : "https://m.tuniucdn.com/fb2/t1/G6/M00/52/10/Cii-U13ePtuIMRSjAAFZ58NGQrMAAGKMgADZ1QAAVn_167_w200_h200_c1_t0.jpg",
  68.               "suggestion" : [
  69.                 "希尔顿",
  70.                 "首都机场",
  71.                 "新国展地区"
  72.               ]
  73.             }
  74.           }
  75.         ]
  76.       }
  77.     ]
  78.   }
  79. }
复制代码
至此本文就全部介绍完了,如果觉得对您有所启发请记得点个赞哦!!!
 
Demo源码:
  1. 链接:https://pan.baidu.com/s/15y_laomAAag6Ruo7I0EMGw
  2. 提取码:et4b
复制代码
此文由博主精心撰写转载请保留此原文链接:https://www.cnblogs.com/xyh9039/p/18063462
版权声明:如有雷同纯属巧合,如有侵权请及时联系本人修改,谢谢!!!

来源:https://www.cnblogs.com/xyh9039/p/18063462
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具