当前位置:   article > 正文

springboot整合elasticsearch5.x以及IK分词器做全文检索_springboot elasticsearch 使用ik analyzer查询

springboot elasticsearch 使用ik analyzer查询

文章我会分三部分来讲解:

第一部分,window下搭建elasticsearch的环境,以及其他插件

第二部分,springboot整合elasticsearch(有一定的分词能力)

第三部分,springboot整合elasticsearch以及ik分词器,做全字段检索(完全分词)

(我的第二篇,《springboot2.x 整合 elasticsearch 创建索引的方式》有更实用的意义,弃用postman创建索引方式,附上项目GitHub地址

一:window安装部署elasticsearch和elasticsearch-head

现在直接在window下安装部署elasticsearch5.5.3。

这里是下载elasticsearch的官网网址:Download Elasticsearch | Elastic

步骤如下:

接着到github主页,下载相应的版本的zip压缩包。

然后解压到磁盘的某个路径,路径不要包含中文字符。

然后进入bin目录下,双击elasticsearch.bat文件,启动elasticsearch。也可以用控制台,输入elasticsearch.bat,然后按回车键,启动elasticsearch。

启动完成后,在浏览器,输入localhost:9200。查看启动效果,如下图,则表示安装启动elasticsearch5.5.3成功。

接下来,对elasticsearch5.5.3进行一些配置,让elasticsearch-head可以访问elasticsearch。elasticsearch-head是让elasticsearch数据可视化的插件。

在window下使用elasticsearch-head插件,要有node.js环境

安装node.js: node.js下载:Download | Node.js 

安装grunt: 

  • grunt是一个很方便的构建工具,可以进行打包压缩、测试、执行等等的工作,5.x里的head插件就是通过grunt启动的。因此需要安装grunt
  • 注意:路径切到nodejs安装目录下,[我安装在C:\Program Files\nodejs],输入命令: npm install -g grunt-cli
  • -g代表全局安装
  • 查看版本号, 输入命令:grunt -version

elasticsearch-head的下载官网网址:GitHub - mobz/elasticsearch-head: A web front end for an elastic search cluster

同样下载zip包,然后指定路径解压,路径也不要有中文字符。(我是将elasticsearch和elasticsearch-head放在E盘路径下)。

①:修改elasticsearch-head配置,找到 elasticsearch-head-master下的Gruntfile.js,文件, 新增:hostname: '0.0.0.0'.

  1. connect: {
  2. server: {
  3. options: {
  4. hostname: '0.0.0.0',
  5. port: 9100,
  6. base: '.',
  7. keepalive: true
  8. }
  9. }
  10. }

②: 修改elasticsearch的配置文件,进入elasticsearch的config目录下,修改elasticsearch.yml文件里面的配置。

  1. cluster.name: elasticsearch
  2. node.name: node-es
  3. network.host: 127.0.0.1
  4. http.port: 9200
  5. transport.tcp.port: 9300
  6. # 增加新的参数,这样head插件就可以访问es
  7. http.cors.enabled: true
  8. http.cors.allow-origin: "*"

上面7行配置代码,全部都是需要往elasticsearch.yml新增的配置,我特意将它们分割三部分。第一部分的配置,可以在启动elasticsearch之后的页面直接能看到(如我上面启动后截图的①②所示)。 最后两个,http.cors.enabled: true, 和 http.cors.allow-origin: "*", 是让head插件访问链接用的配置,不可缺少。

重启elasticsearch。接着在elasticsearch-head-master的目录下,输入命令:grunt server,启动head插件

然后在浏览器输入: localhost:9100

到这里,elasticsearch和elasticsearch-head的安装与配置已经完成。

elasticsearch以及elasticsearch-head的安装与配置,推荐一个网址,这个哥们写得很好,我的配置都是按他的来配置的:在Windows上安装Elasticsearch 5.x - 秦岭过客 - 博客园

二:springboot整合elasticsearch

到springboot官网看你就知道,整合elasticsearch有三种方式:

  1. Connecting to Elasticsearch by REST clients
  2. Connecting to Elasticsearch by Using Jest
  3. Connecting to Elasticsearch by Using Spring Data

这里我是使用第三种方式,spring Data elasticsearch

新建一个springboot工程,我的springboot版本是2.0.0

我的pom.xml文件

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <parent>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-parent</artifactId>
  8. // 可以直接在这里修改你的springboot版本,我的springboot新建时是2.1.6的,然后在这里修改为2.0.0
  9. <version>2.0.0.RELEASE</version>
  10. <relativePath/>
  11. </parent>
  12. <groupId>com.gosuncn</groupId>
  13. <artifactId>esdemo</artifactId>
  14. <version>0.0.1-SNAPSHOT</version>
  15. <name>esdemo</name>
  16. <description>Demo project for Spring Boot</description>
  17. <properties>
  18. <java.version>1.8</java.version>
  19. <elasticsearch.version>5.5.3</elasticsearch.version>
  20. </properties>
  21. <dependencies>
  22. <dependency>
  23. <groupId>org.springframework.boot</groupId>
  24. <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
  25. </dependency>
  26. <dependency>
  27. <groupId>org.elasticsearch.client</groupId>
  28. <artifactId>transport</artifactId>
  29. <version>5.5.3</version>
  30. </dependency>
  31. <dependency>
  32. <groupId>org.springframework.boot</groupId>
  33. <artifactId>spring-boot-starter-web</artifactId>
  34. </dependency>
  35. <dependency>
  36. <groupId>org.projectlombok</groupId>
  37. <artifactId>lombok</artifactId>
  38. <optional>true</optional>
  39. </dependency>
  40. <dependency>
  41. <groupId>org.springframework.boot</groupId>
  42. <artifactId>spring-boot-starter-test</artifactId>
  43. <scope>test</scope>
  44. </dependency>
  45. </dependencies>
  46. <build>
  47. <plugins>
  48. <plugin>
  49. <groupId>org.springframework.boot</groupId>
  50. <artifactId>spring-boot-maven-plugin</artifactId>
  51. </plugin>
  52. </plugins>
  53. </build>
  54. </project>

然后可以看你springboot导入的elasticsearch.jar的版本

因为spring data elasticsearch 与elasticsearch是要进行版本适配的,不匹配,是不能进行连接的。 

细心的朋友,可能已经发现,我的elasticsearch已经存在一个local_library索引了。那我们就以这个索引为例。

这里,我先说明一下,我的local_library索引是怎样创建的。使用postman,提交PUT请求,即可创建local_library索引,以及这个索引下的book类型。

body实体里面的内容如下:在local_library索引下,创建一个book类型。

  1. {
  2. "mappings":{
  3. "book":{
  4. "properties":{
  5. "book_id":{
  6. "type":"long",
  7. "fields":{
  8. "keyword":{
  9. "type":"keyword"
  10. }
  11. }
  12. },
  13. "book_code":{
  14. "type":"text",
  15. "fields":{
  16. "keyword":{
  17. "type":"keyword"
  18. }
  19. }
  20. },
  21. "book_name":{
  22. "type":"text",
  23. "fields":{
  24. "keyword":{
  25. "type":"keyword"
  26. }
  27. }
  28. },
  29. "book_price":{
  30. "type":"integer",
  31. "fields":{
  32. "keyword":{
  33. "type":"keyword"
  34. }
  35. }
  36. },
  37. "book_author":{
  38. "type":"text",
  39. "fields":{
  40. "keyword":{
  41. "type":"keyword"
  42. }
  43. }
  44. },
  45. "book_desc":{
  46. "type":"text",
  47. "fields":{
  48. "keyword":{
  49. "type":"keyword"
  50. }
  51. }
  52. }
  53. }
  54. }
  55. }
  56. }

在elasticsearch-head查看效果如下:(备注:)

接着,有索引,有类型了,可以开始插入数据。插入数据有两种方式,第一种是用postman, 第二种是在springboot工程的测试类中插入。

①:用postman插入数据示例:

插入的效果,可以看上面数据截图。

②:用实体类插入数据(包括新增、查询)

新建一个Library实体类:(备注,实体类已经使用lombok插件了)

  1. @Data
  2. @NoArgsConstructor
  3. @AllArgsConstructor
  4. @Document(indexName = "local_library", type = "book")
  5. public class Library {
  6. /**
  7. * index:是否设置分词
  8. * analyzer:存储时使用的分词器
  9. * ik_max_word
  10. * ik_word
  11. * searchAnalyze:搜索时使用的分词器
  12. * store:是否存储
  13. * type: 数据类型
  14. */
  15. @Id
  16. private Integer book_id;
  17. private String book_code;
  18. private String book_name;
  19. private Integer book_price;
  20. private String book_author;
  21. private String book_desc;
  22. }

然后编写一个LibraryRepository:

  1. @Repository
  2. public interface LibraryRepository extends ElasticsearchRepository<Library, Long> {
  3. }

然后在测试类中,插入数据:

  1. import com.gosuncn.esdemo.domin.Library;
  2. import com.gosuncn.esdemo.repository.LibraryRepository;
  3. import org.elasticsearch.index.query.QueryBuilders;
  4. import org.elasticsearch.index.query.QueryStringQueryBuilder;
  5. import org.junit.Test;
  6. import org.junit.runner.RunWith;
  7. import org.springframework.beans.factory.annotation.Autowired;
  8. import org.springframework.boot.test.context.SpringBootTest;
  9. import org.springframework.data.domain.Page;
  10. import org.springframework.data.domain.PageRequest;
  11. import org.springframework.data.domain.Sort;
  12. import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
  13. import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
  14. import org.springframework.test.context.junit4.SpringRunner;
  15. import java.util.ArrayList;
  16. import java.util.Iterator;
  17. import java.util.List;
  18. @RunWith(SpringRunner.class)
  19. @SpringBootTest
  20. public class EsdemoApplicationTests {
  21. @Autowired
  22. ElasticsearchTemplate elasticsearchTemplate;
  23. @Autowired
  24. LibraryRepository libraryRepository;
  25. /**
  26. * 插入数据
  27. */
  28. @Test
  29. public void testInsert(){
  30. libraryRepository.save(new Library(42, "A00042", "明史简述", 59, "吴晗", "吴晗背景uniworsity厉害"));
  31. libraryRepository.save(new Library(43, "A00043", "傅雷家书", 99, "傅聪", "都是NB,class大家u"));
  32. libraryRepository.save(new Library(24, "A00942", "时间简史", 169, "霍金", "教授宇宙大爆发的59年历史"));
  33. libraryRepository.save(new Library(25, "A00925", "我的前半生", 39, "方舟89子", "都是生活,每晚9点"));
  34. libraryRepository.save(new Library(29, "A00029", "围9城", 139, "钱钟书", "你想出城?不存在的"));
  35. }
  36. }

到此,这是第二种插入数据的方式。

然后数据有了,就可以进行查询了。查询代码如下:

  1. // 全字段查询,不分页
  2. @Test
  3. public void testSearch(){
  4. try {
  5. String searchStr = "三西阿";
  6. QueryStringQueryBuilder builder = new QueryStringQueryBuilder(searchStr);
  7. Iterable<Library> search = libraryRepository.search(builder);
  8. Iterator<Library> iterator = search.iterator();
  9. while (iterator.hasNext()){
  10. System.out.println("--> 数据:"+iterator.next());
  11. }
  12. }catch (Exception e){
  13. System.out.println("---> 异常信息: "+e);
  14. }
  15. }
  16. // 全字段查询, 已经分页
  17. @Test
  18. public void testSearchByPage(){
  19. try {
  20. String searchStr = "三西阿";
  21. QueryStringQueryBuilder builder = new QueryStringQueryBuilder(searchStr);
  22. Iterable<Library> search = libraryRepository.search(builder, PageRequest.of(0,2));
  23. Iterator<Library> iterator = search.iterator();
  24. while (iterator.hasNext()){
  25. System.out.println("--> 数据:"+iterator.next());
  26. }
  27. }catch (Exception e){
  28. System.out.println("---> 异常信息: "+e);
  29. }
  30. }

运行第一个test的结果是:

  1. --> 数据:Library{book_id=3, book_code='A0003', book_name='西游记', book_price=99, book_author='吴承恩', book_desc='冒险小说!'}
  2. --> 数据:Library{book_id=6, book_code='A0006', book_name='欢乐颂', book_price=399, book_author='阿耐', book_desc='都是生活真实隐射!'}
  3. --> 数据:Library{book_id=7, book_code='A0007', book_name='都挺好', book_price=299, book_author='阿耐', book_desc='折射现实家庭矛盾!'}
  4. --> 数据:Library{book_id=5, book_code='A0005', book_name='三国演义', book_price=198, book_author='罗贯中', book_desc='三国霸王游戏!'}
  5. --> 数据:Library{book_id=18, book_code='A00018', book_name='编译原理', book_price=79, book_author='赵建华', book_desc='三十多小时,98.5'}
  6. --> 数据:Library{book_id=1, book_code='A0001', book_name='琴帝', book_price=180, book_author='唐家三少', book_desc='最好看的玄幻小说!'}
  7. --> 数据:Library{book_id=12, book_code='A00012', book_name='三重门', book_price=69, book_author='韩寒', book_desc='这是一个批评现实的真实故事'}

三:IK分词器的使用

前面的都是小case,到这里才是我们做全文检索的重点。

3.1:为什么要使用IK分词器

ik分词器,会将你的查询条件语句拆分成一个一个词。比如:查询语句是“我爱中华人民共和国”,使用ik_max_word来分词,则会出现下面的结果: 【“我”,“爱”,“中华人民共和国”,“中华人民”,“中华”,“华人”,“人民共和国”,“人民”,“人民共和国”,“共和”,“国”】。具体看下图:(使用postman)

body结果代码如下:

  1. {
  2. "tokens": [
  3. {
  4. "token": "我",
  5. "start_offset": 0,
  6. "end_offset": 1,
  7. "type": "CN_CHAR",
  8. "position": 0
  9. },
  10. {
  11. "token": "爱",
  12. "start_offset": 1,
  13. "end_offset": 2,
  14. "type": "CN_CHAR",
  15. "position": 1
  16. },
  17. {
  18. "token": "中华人民共和国",
  19. "start_offset": 2,
  20. "end_offset": 9,
  21. "type": "CN_WORD",
  22. "position": 2
  23. },
  24. {
  25. "token": "中华人民",
  26. "start_offset": 2,
  27. "end_offset": 6,
  28. "type": "CN_WORD",
  29. "position": 3
  30. },
  31. {
  32. "token": "中华",
  33. "start_offset": 2,
  34. "end_offset": 4,
  35. "type": "CN_WORD",
  36. "position": 4
  37. },
  38. {
  39. "token": "华人",
  40. "start_offset": 3,
  41. "end_offset": 5,
  42. "type": "CN_WORD",
  43. "position": 5
  44. },
  45. {
  46. "token": "人民共和国",
  47. "start_offset": 4,
  48. "end_offset": 9,
  49. "type": "CN_WORD",
  50. "position": 6
  51. },
  52. {
  53. "token": "人民",
  54. "start_offset": 4,
  55. "end_offset": 6,
  56. "type": "CN_WORD",
  57. "position": 7
  58. },
  59. {
  60. "token": "共和国",
  61. "start_offset": 6,
  62. "end_offset": 9,
  63. "type": "CN_WORD",
  64. "position": 8
  65. },
  66. {
  67. "token": "共和",
  68. "start_offset": 6,
  69. "end_offset": 8,
  70. "type": "CN_WORD",
  71. "position": 9
  72. },
  73. {
  74. "token": "国",
  75. "start_offset": 8,
  76. "end_offset": 9,
  77. "type": "CN_CHAR",
  78. "position": 10
  79. }
  80. ]
  81. }

补充说明一下的区别:ik_max_word 和 ik_smart 

  1. ik_max_word 会将文本做最细粒度的拆分。
  2. ik_smart 会做最粗粒度的拆分。

ik_max_word  和 ik_smart 是两个不同类型的分词器。

3.2 安装ik分词器

ik分词器的下载与安装:(备注:ik分词器的版本,必须与elasticsearch版本一致

GitHub下载地址: Releases · medcl/elasticsearch-analysis-ik · GitHub

找到5.5.3版本的

点击下载elasticsearch-analysis-ik-5.5.3.zip 包,然后解压,打开解压后的文件夹,里面有如下文件

接着,把这里的所有文件复制到elasticsearch的plugins目录下,自己新建的ik文件夹里面(说明: ik文件夹是自己新建的,至于为什么要新建一个ik文件夹。其实到后来,你会在使用elasticsearch时添加很多的插件,每一个插件都是放在plugins目录下的,所以建一个文件夹,单独存放某个插件,会有一个很清晰的文件目录)

然后重启elasticsearch。

出现红圈所示,则说明插件安装成功。

检验效果:启动elasticsearch成功后,直接在浏览器输入:http://localhost:9200/_analyze?analyzer=ik_max_word&pretty=true&text=我爱中华人民共和国

备注:

如果是ik分词插件是6.x版本的,只能用postman测试,而且查询条件要放在body体内,如下图:

如果直接在url加上查询条件,如: http://localhost:9200/_analyze?analyzer=ik_max_word&pretty=true&text=大胆爱,不用地阿达女,加

会抛出异常:

  1. {
  2. "error": {
  3. "root_cause": [
  4. {
  5. "type": "parse_exception",
  6. "reason": "request body or source parameter is required"
  7. }
  8. ],
  9. "type": "parse_exception",
  10. "reason": "request body or source parameter is required"
  11. },
  12. "status": 400
  13. }

3.3 自定义分词器

上面说的ik_max_word 和ik_smart 这两种分词器,其实不是我想要的效果。比如我要查询“cla好好学习,15成功”。

浏览器输入:http://localhost:9200/_analyze?analyzer=ik_max_word&pretty=true&text=cla好好学习,15成功

我想要将查询条件分拆成:【"c", "l", "a", "好", "好", "学", "习", ",", "1", "5", "成", "功"】这种,单个字,单个词,单个数字的最小粒度。但是ik_max_word 已经是不能满足我的需求了,那我们就自定义一个分词器(analyzer)

使用NGram 来定义一个分词器: 官网:NGram Tokenizer | Elasticsearch Guide [6.4] | Elastic

这个网址里面的内容很重要,看不懂英文的小伙伴,可以用浏览器的插件,将它翻译成中文。

这句话:They are useful for querying languages that don’t use spaces or that have long compound words, like German.

意思是:它们对于查询不使用空格或具有长复合词的语言非常有用,比如德语。

我就直接使用官网的例子进行说明:输入的查询条件是:“Quick Fox”.

  1. POST _analyze
  2. {
  3. "tokenizer": "ngram",
  4. "text": "Quick Fox"
  5. }

分词后的结果是:

[ Q, Qu, u, ui, i, ic, c, ck, k, "k ", " ", " F", F, Fo, o, ox, x ]

可以给 ngram 配置下面三个参数:

①:min_gram :字符的最小长度,默认是1.

②:max_gram:字符的最大长度,默认是2.

③:token_chars: 可以理解为elasticsearch分割字符的点。其中又可以包含5个属性。letter ,digit ,whitespace ,punctuation ,symbol 。

知道这些配置后,开始实例:(实例里面,自定义一个 myanalyzer 分词器,并创建my_user索引,和user类型)

  1. PUT localhost:9200/my_user/
  2. {
  3. "settings": {
  4. "analysis": {
  5. "analyzer": {
  6. "myanalyzer": {
  7. "tokenizer": "mytokenizer"
  8. }
  9. },
  10. "tokenizer": {
  11. "mytokenizer": {
  12. "type": "ngram",
  13. "min_gram": 1,
  14. "max_gram": 2,
  15. "token_chars": [
  16. "letter",
  17. "digit",
  18. "whitespace",
  19. "punctuation",
  20. "symbol"
  21. ]
  22. }
  23. }
  24. }
  25. },
  26. "mappings":{
  27. "user":{
  28. "properties":{
  29. "id":{
  30. "type":"long",
  31. "store": true,
  32. "index": false,
  33. "fields":{
  34. "keyword":{
  35. "type":"keyword"
  36. }
  37. }
  38. },
  39. "username":{
  40. "type":"text",
  41. "store": true,
  42. "index": true,
  43. "analyzer": "myanalyzer",
  44. "fields":{
  45. "keyword":{
  46. "type":"keyword"
  47. }
  48. }
  49. },
  50. "password":{
  51. "type":"text",
  52. "store": true,
  53. "index": true,
  54. "analyzer": "myanalyzer",
  55. "fields":{
  56. "keyword":{
  57. "type":"keyword"
  58. }
  59. }
  60. },
  61. "age":{
  62. "type":"integer",
  63. "fields":{
  64. "keyword":{
  65. "type":"keyword"
  66. }
  67. }
  68. },
  69. "ip":{
  70. "type":"text",
  71. "store": true,
  72. "index": true,
  73. "analyzer": "myanalyzer",
  74. "fields":{
  75. "keyword":{
  76. "type":"keyword"
  77. }
  78. }
  79. }
  80. }
  81. }
  82. }
  83. }

postman截图:

或者可以使用这种方式:

  1. POST localhost:9200/my_user/_analyze?analyzer=myanalyzer&pretty=true
  2. {
  3. "text": "2 Quick Fo18陈xes姥爷."
  4. }

接着用postman查询构建的这个my_user索引,类型为user。

  1. POST localhost:9200/my_user/_analyze
  2. {
  3. "analyzer": "myanalyzer",
  4. "text": "2 Quick Fo18陈xes姥爷."
  5. }
  6. // 结果
  7. {
  8. "tokens": [
  9. {
  10. "token": "2",
  11. "start_offset": 0,
  12. "end_offset": 1,
  13. "type": "word",
  14. "position": 0
  15. },
  16. {
  17. "token": "2 ",
  18. "start_offset": 0,
  19. "end_offset": 2,
  20. "type": "word",
  21. "position": 1
  22. },
  23. {
  24. "token": " ",
  25. "start_offset": 1,
  26. "end_offset": 2,
  27. "type": "word",
  28. "position": 2
  29. },
  30. {
  31. "token": " Q",
  32. "start_offset": 1,
  33. "end_offset": 3,
  34. "type": "word",
  35. "position": 3
  36. },
  37. {
  38. "token": "Q",
  39. "start_offset": 2,
  40. "end_offset": 3,
  41. "type": "word",
  42. "position": 4
  43. },
  44. {
  45. "token": "Qu",
  46. "start_offset": 2,
  47. "end_offset": 4,
  48. "type": "word",
  49. "position": 5
  50. },
  51. {
  52. "token": "u",
  53. "start_offset": 3,
  54. "end_offset": 4,
  55. "type": "word",
  56. "position": 6
  57. },
  58. {
  59. "token": "ui",
  60. "start_offset": 3,
  61. "end_offset": 5,
  62. "type": "word",
  63. "position": 7
  64. },
  65. {
  66. "token": "i",
  67. "start_offset": 4,
  68. "end_offset": 5,
  69. "type": "word",
  70. "position": 8
  71. },
  72. {
  73. "token": "ic",
  74. "start_offset": 4,
  75. "end_offset": 6,
  76. "type": "word",
  77. "position": 9
  78. },
  79. {
  80. "token": "c",
  81. "start_offset": 5,
  82. "end_offset": 6,
  83. "type": "word",
  84. "position": 10
  85. },
  86. {
  87. "token": "ck",
  88. "start_offset": 5,
  89. "end_offset": 7,
  90. "type": "word",
  91. "position": 11
  92. },
  93. {
  94. "token": "k",
  95. "start_offset": 6,
  96. "end_offset": 7,
  97. "type": "word",
  98. "position": 12
  99. },
  100. {
  101. "token": "k ",
  102. "start_offset": 6,
  103. "end_offset": 8,
  104. "type": "word",
  105. "position": 13
  106. },
  107. {
  108. "token": " ",
  109. "start_offset": 7,
  110. "end_offset": 8,
  111. "type": "word",
  112. "position": 14
  113. },
  114. {
  115. "token": " F",
  116. "start_offset": 7,
  117. "end_offset": 9,
  118. "type": "word",
  119. "position": 15
  120. },
  121. {
  122. "token": "F",
  123. "start_offset": 8,
  124. "end_offset": 9,
  125. "type": "word",
  126. "position": 16
  127. },
  128. {
  129. "token": "Fo",
  130. "start_offset": 8,
  131. "end_offset": 10,
  132. "type": "word",
  133. "position": 17
  134. },
  135. {
  136. "token": "o",
  137. "start_offset": 9,
  138. "end_offset": 10,
  139. "type": "word",
  140. "position": 18
  141. },
  142. {
  143. "token": "o1",
  144. "start_offset": 9,
  145. "end_offset": 11,
  146. "type": "word",
  147. "position": 19
  148. },
  149. {
  150. "token": "1",
  151. "start_offset": 10,
  152. "end_offset": 11,
  153. "type": "word",
  154. "position": 20
  155. },
  156. {
  157. "token": "18",
  158. "start_offset": 10,
  159. "end_offset": 12,
  160. "type": "word",
  161. "position": 21
  162. },
  163. {
  164. "token": "8",
  165. "start_offset": 11,
  166. "end_offset": 12,
  167. "type": "word",
  168. "position": 22
  169. },
  170. {
  171. "token": "8陈",
  172. "start_offset": 11,
  173. "end_offset": 13,
  174. "type": "word",
  175. "position": 23
  176. },
  177. {
  178. "token": "陈",
  179. "start_offset": 12,
  180. "end_offset": 13,
  181. "type": "word",
  182. "position": 24
  183. },
  184. {
  185. "token": "陈x",
  186. "start_offset": 12,
  187. "end_offset": 14,
  188. "type": "word",
  189. "position": 25
  190. },
  191. {
  192. "token": "x",
  193. "start_offset": 13,
  194. "end_offset": 14,
  195. "type": "word",
  196. "position": 26
  197. },
  198. {
  199. "token": "xe",
  200. "start_offset": 13,
  201. "end_offset": 15,
  202. "type": "word",
  203. "position": 27
  204. },
  205. {
  206. "token": "e",
  207. "start_offset": 14,
  208. "end_offset": 15,
  209. "type": "word",
  210. "position": 28
  211. },
  212. {
  213. "token": "es",
  214. "start_offset": 14,
  215. "end_offset": 16,
  216. "type": "word",
  217. "position": 29
  218. },
  219. {
  220. "token": "s",
  221. "start_offset": 15,
  222. "end_offset": 16,
  223. "type": "word",
  224. "position": 30
  225. },
  226. {
  227. "token": "s姥",
  228. "start_offset": 15,
  229. "end_offset": 17,
  230. "type": "word",
  231. "position": 31
  232. },
  233. {
  234. "token": "姥",
  235. "start_offset": 16,
  236. "end_offset": 17,
  237. "type": "word",
  238. "position": 32
  239. },
  240. {
  241. "token": "姥爷",
  242. "start_offset": 16,
  243. "end_offset": 18,
  244. "type": "word",
  245. "position": 33
  246. },
  247. {
  248. "token": "爷",
  249. "start_offset": 17,
  250. "end_offset": 18,
  251. "type": "word",
  252. "position": 34
  253. },
  254. {
  255. "token": "爷.",
  256. "start_offset": 17,
  257. "end_offset": 19,
  258. "type": "word",
  259. "position": 35
  260. },
  261. {
  262. "token": ".",
  263. "start_offset": 18,
  264. "end_offset": 19,
  265. "type": "word",
  266. "position": 36
  267. }
  268. ]
  269. }

postman截图:

得到的结果是:分词成功。

3.4 重新构建springboot使用myanalyzer分词器,做全文检索

新建一个User实体:(对应elasticsearch中的my_user索引,和user类型)

  1. @Data
  2. @NoArgsConstructor
  3. @AllArgsConstructor
  4. @Document(indexName = "my_user", type = "user")
  5. public class User {
  6. /**
  7. * index:是否设置分词
  8. * analyzer:存储时使用的分词器
  9. * searchAnalyze:搜索时使用的分词器
  10. * store:是否存储
  11. * type: 数据类型
  12. */
  13. @Id
  14. @Field(store = true, index = false, type =FieldType.Integer)
  15. private Integer id;
  16. @Field(store = true, index = true, type = FieldType.keyword, analyzer = "myanalyzer", searchAnalyzer = "myanalyzer")
  17. private String username;
  18. @Field(store = true, index = true, type = FieldType.keyword, analyzer = "myanalyzer", searchAnalyzer = "myanalyzer")
  19. private String password;
  20. @Field(store = true, index = true, type = FieldType.Integer, analyzer = "myanalyzer", searchAnalyzer = "myanalyzer")
  21. private Integer age;
  22. @Field(store = true, index = true, type = FieldType.keyword, analyzer = "myanalyzer", searchAnalyzer = "myanalyzer")
  23. private String ip;
  24. }

新建UserRepository接口。

  1. @Repository
  2. public interface UserRepository extends ElasticsearchRepository<User, Long> {
  3. }

在测试类中进行测试: (插入数据)

  1. @RunWith(SpringRunner.class)
  2. @SpringBootTest
  3. public class UserTest {
  4. @Autowired
  5. UserRepository userRepository;
  6. // 插入数据
  7. @Test
  8. public void testInsert(){
  9. userRepository.save(new User(3, "高新兴", "gao45", 18, "我登录的ip地址是:127.145.0.11"));
  10. userRepository.save(new User(4, "神州@数码", "shen18", 18, "我登录的ip地址是:127.124.0.11"));
  11. userRepository.save(new User(6, "西南大学", "xida", 18, "我登录的ip地址是:127.126.0.11"));
  12. userRepository.save(new User(7, "北京大学", "beida", 18, "我记录的ip地址是:127.127.0.11"));
  13. userRepository.save(new User(8, "姚#明", "yao210", 18, "我登录的@#%ip地址是:127.248.0.11"));
  14. userRepository.save(new User(9, "邓紫棋", "dengml", 18, "我使用的ip地址是:127.249.0.11"));
  15. userRepository.save(new User(10, "李荣浩", "li06", 18, "我使用的@ip地址是:127.234.0.11"));
  16. userRepository.save(new User(11, "陈奕迅", "19ch8en", 18, "我登录的ip地址是:127.219.0.11"));
  17. userRepository.save(new User(12, "周杰伦", "xiayu2014", 18, "我登录的ip地址是:127.0.0.11"));
  18. userRepository.save(new User(13, "林俊杰", "zho99", 18, "我登录,的ip地址是:127.111.0.11"));
  19. userRepository.save(new User(137, "林薇因", "zho99", 18, "我登录,的ip地址是:127.111.0.11"));
  20. }

插入数据后, elasticsearch里面的数据显示如下:

查询数据:

  1. @Test
  2. public void testQueryByStr(){
  3. try {
  4. String searchStr = "陈夏天u马立,@45";
  5. QueryStringQueryBuilder builder = new QueryStringQueryBuilder(searchStr);
  6. // 重点是下面这行代码
  7. builder.analyzer("myanalyzer").field("username").field("password").field("ip");
  8. Iterable<User> search = userRepository.search(builder);
  9. Iterator<User> iterator = search.iterator();
  10. while (iterator.hasNext()){
  11. System.out.println("---> 匹配数据: "+iterator.next());
  12. }
  13. }catch (Exception e){
  14. System.out.println("---> 异常信息 "+e);
  15. }
  16. }

查询结果:

  1. ---> 匹配数据: User(id=33, username=陈%喜华, password=gao45, age=18, ip=我登录的ip地址是:127.145.0.11)
  2. ---> 匹配数据: User(id=3, username=高新兴, password=gao45, age=18, ip=我登录的ip地址是:127.145.0.11)
  3. ---> 匹配数据: User(id=35, username=马@,#立志, password=ling009, age=18, ip=我记录的ip地址是:127.125.0.11)
  4. ---> 匹配数据: User(id=48, username=郭才莹, password=yao210, age=18, ip=我登录的,@#%ip地址是:127.248.0.11)
  5. ---> 匹配数据: User(id=126, username=夏雨, password=xiayu2014, age=18, ip=我登录的ip地址是:127.0.0.11)
  6. ---> 匹配数据: User(id=12, username=周杰伦, password=xiayu2014, age=18, ip=我登录的ip地址是:127.0.0.11)
  7. ---> 匹配数据: User(id=115, username=朱&@#%夏宇, password=19ch8en, age=18, ip=我登录的ip地址是:127.219.0.11)
  8. ---> 匹配数据: User(id=8, username=姚#明, password=yao210, age=18, ip=我登录的@#%ip地址是:127.248.0.11)
  9. ---> 匹配数据: User(id=10, username=李荣浩, password=li06, age=18, ip=我使用的@ip地址是:127.234.0.11)
  10. ---> 匹配数据: User(id=104, username=黄小群, password=li06, age=18, ip=我使用的@ip地址是:127.234.0.11)
  11. ---> 匹配数据: User(id=36, username=陈耀鹏, password=xida, age=18, ip=我登录的ip地址是:127.126.0.11)
  12. ---> 匹配数据: User(id=11, username=陈奕迅, password=19ch8en, age=18, ip=我登录的ip地址是:127.219.0.11)
  13. ---> 匹配数据: User(id=137, username=林薇因, password=zho99, age=18, ip=我登录,的ip地址是:127.111.0.11)
  14. ---> 匹配数据: User(id=13, username=林俊杰, password=zho99, age=18, ip=我登录,的ip地址是:127.111.0.11)
  15. ---> 匹配数据: User(id=4, username=神州@数码, password=shen18, age=18, ip=我登录的ip地址是:127.124.0.11)
  16. ---> 匹配数据: User(id=5, username=岭南师范, password=ling009, age=18, ip=我记录的ip地址是:127.125.0.11)
  17. ---> 匹配数据: User(id=9, username=邓紫棋, password=dengml, age=18, ip=我使用的ip地址是:127.249.0.11)
  18. ---> 匹配数据: User(id=34, username=钟楚莹, password=shen18, age=18, ip=我登录的ip地址是:127.124.0.11)
  19. ---> 匹配数据: User(id=49, username=黄群, password=dengml, age=18, ip=我使用的ip地址是:127.249.0.11)

到处,springboot整合elasticsearch以及ik分词器,做全文检索完成了。

先告一段落,文章写得不是很好。但希望你能看懂。如果有不懂的,底下留言。我会及时更新

希望此文帮助到你!

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/604535
推荐阅读
相关标签
  

闽ICP备14008679号