飞道的博客

一篇就懂 Elasticsearch | 原力计划

369人阅读  评论(0)

作者 | mr_xinchen

来源 | CSDN博客

出品 | CSDN(ID:CSDNnews)

Elasticsearch介绍

Elasticsearch是一款基于Lucene的分布式全文检索服务器,让我们看一下百度文库给出的解释。

用途:做搜索功能

使用案例:GitHub、维基百科、等等

Solr对比:

  • 实时性ES高于Solr

  • Solr传统搜索性能高于ES

Elasticsearch安装

注意:安装必须在java1.8版本以上Windows环境

  1. 去官网下载获得压缩包一个,版本6.2.4

  2. 解压缩进入目录找到bin文件夹

  3. 双击运行bin文件夹中elasticsearch.bat脚本

  4. 在浏览器输入http://localhost:9200/

安装成功浏览器显示

Linux环境

1. 安装和配置

我们将在linux下安装Elasticsearch,使用版本6.2.4

2. 新建一个用户

出于安全考虑,elasticsearch默认不允许以root账号运行。

创建用户:

1useradd 用户名

设置密码:


   
  1. 1passwd 用户名

切换用户:

1su 用户名

3. 上传安装包,并解压

我们将安装包上传到:/home/用户名目录

解压缩:

1tar -zxvf elasticsearch-6.2.4.tar.gz

我们把目录重命名:

1mv elasticsearch-6.2.4/ elasticsearch

进入,查看目录结构:

1ls -l /home/用户名/elasticsearch

4. 修改配置

我们进入config目录:cd config

需要修改的配置文件有两个:

jvm.options

Elasticsearch基于Lucene的,而Lucene底层是java实现,因此我们需要配置jvm参数。

编辑jvm.options:

1vim jvm.options

默认配置如下:


   
  1. 1-Xms1g
  2. 2-Xmx1g

内存占用太多了,我们调小一些:


   
  1. 1-Xms512m
  2. 2-Xmx512m

elasticsearch.yml

1vim elasticsearch.yml
  • 修改数据和日志目录:


   
  1. 1path.data: /home/用户名/elasticsearch/data  # 数据目录位置
  2. 2path.logs: /home/用户名/elasticsearch/logs  # 日志目录位置

我们把data和logs目录修改指向了elasticsearch的安装目录。但是这两个目录并不存在,因此我们需要创建出来。

进入elasticsearch的根目录,然后创建:


   
  1. 1mkdir data
  2. 2mkdir logs
  • 修改绑定的ip:

1network.host: 0.0.0.0 # 绑定到0.0.0.0,允许任何ip来访问

默认只允许本机访问,修改为0.0.0.0后则可以远程访问

目前我们是做的单机安装,如果要做集群,只需要在这个配置文件中添加其它节点信息即可。

elasticsearch.yml的其它可配置信息:

5. 运行

进入elasticsearch/bin目录,可以看到下面的执行文件:

然后输入命令:

1./elasticsearch

发现报错了,启动失败:

  • 错误1:内核过低

我们使用的是centos6,其linux内核版本为2.6。而Elasticsearch的插件要求至少3.5以上版本。不过没关系,我们禁用这个插件即可。

修改elasticsearch.yml文件,在最下面添加如下配置:

1bootstrap.system_call_filter: false

然后重启

  • 错误2:文件权限不足

再次启动,又出错了:

1[1]: max file descriptors [4096for elasticsearch process likely too low, increase to at least [65536]

我们用的是普通用户,而不是root,所以文件权限不足。

首先用root用户登录。

然后修改配置文件:

1vim /etc/security/limits.conf

添加下面的内容:


   
  1. 1* soft nofile  65536
  2. 2
  3. 3* hard nofile  131072
  4. 4
  5. 5* soft nproc  4096
  6. 6
  7. 7* hard nproc  4096
  • 错误3:线程数不够

刚才报错中,还有一行:

1[1]: max number of threads [1024for user [leyou] is too low, increase to at least [4096]

这是线程数不够。

继续修改配置:


   
  1. 1vim /etc/security/limits.d/ 90-nproc.conf 

修改下面的内容:

1* soft nproc 1024

改为:

1* soft nproc 4096
  • 错误4:进程虚拟内存

1[3]: max virtual memory areas vm.max_map_count [65530] likely too low, increase to at least [262144]

vm.max_map_count:限制一个进程可以拥有的VMA(虚拟内存区域)的数量,继续修改配置文件, :

1vim /etc/sysctl.conf 

添加下面内容:

1vm.max_map_count=655360

然后执行命令:

1sysctl -p

6. 重启终端窗口

所有错误修改完毕,一定要重启你的 Xshell终端,否则配置无效。

7. 启动

进入elasticsearch/bin目录,然后输入命令:

1./elasticsearch

可以看到绑定了两个端口:

  • 9300:集群节点间通讯接口

  • 9200:客户端访问接口

我们在浏览器中访问:http://127.0.0.1:9200

Elasticsearch理论知识

看过我上篇Lucene的文章,大家知道我把Lucene和传统数据库对比,其实他们很多相同之处,接下来我们拿Elasticsearch和Mysql进行比较。


   
  1. 1Mysql -> database -> table -> rows -> columns
  2. 2
  3. 3Elasticsearch -> index -> type -> documents -> fields

1. index(索引)

可以类似看成一个database,但区别于就是一个拥有几分相似特征的文档的集合,比如你可以有商品数据索引、或则客户数据索引。

2. type(类型)

可以类似看成一个table,就是给文档分分类用的,通常,会为具有一组共同字段的文档定义一个类型。

3. documents (文档)

可以类似看成一个table下一行数据, 一个文档是一个可被索引的基础信息单元。

4. fields(字段,在lucene中叫域)

可以类似看成一个table的字段,对文档数据根据不同属性进行的分类标识

5. mapping(映射)

可以类似看成字段的数据类型和约束,mapping是处理数据的方式和规则方面做一些限制,如某个字段的数据类型、默认值、分析器、是否被索引等等

6. shards&replicas(分片&备份)

ES是分布式大数据量全文检索服务器,把文档数据切成片段,多个片合在一起是一个完整的数据。在分布式环境中很有就能出现单点故障问题,这时候需要备份每个片段会被复制和转移同步。

RESTfull语法

我这里使用kibana,也可以使用其他工具实现

1. 创建索引index和映射mapping


   
  1. 1PUT /索引名
  2. 2
  3. 3{
  4. 4
  5. 5     "mappings": {
  6. 6
  7. 7         "type名": {
  8. 8
  9. 9             "properties": {
  10. 10
  11. 11                 "fields名": {
  12. 12
  13. 13                  "type""类型",    
  14. 14
  15. 15                     "store": 是否储存[ true, false],
  16. 16
  17. 17                     "index": 是否索引[ true, false],
  18. 18
  19. 19                     "analyzer": "分词器"
  20. 20
  21. 21                },
  22. 22
  23. 23                 "fields名": {
  24. 24
  25. 25                  "type""text",    
  26. 26
  27. 27                     "store"true,
  28. 28
  29. 29                     "index"true,
  30. 30
  31. 31                     "analyzer": "standard"
  32. 32
  33. 33                }
  34. 34
  35. 35            }
  36. 36
  37. 37        }
  38. 38
  39. 39    }
  40. 40
  41. 41}

2. 创建索引index后添加映射mapping


   
  1. 1POST /索引名/type名/_mapping
  2. 2
  3. 3{
  4. 4
  5. 5   "type名":{
  6. 6
  7. 7     "properties":{
  8. 8
  9. 9       "fields名":{
  10. 10
  11. 11         "type": "long",
  12. 12
  13. 13         "store": true,
  14. 14
  15. 15         "index": false
  16. 16
  17. 17      },
  18. 18
  19. 19       "fields名":{
  20. 20
  21. 21         "type": "text",
  22. 22
  23. 23         "store": true,
  24. 24
  25. 25         "index": true,
  26. 26
  27. 27         "analyzer": "standard"
  28. 28
  29. 29      }
  30. 30
  31. 31    }
  32. 32
  33. 33  }
  34. 34
  35. 35}

3. 删除索引index

1DELETE /索引名

4. 添加文档document


   
  1. 1POST /索引名/type名/[_id]
  2. 2
  3. 3{
  4. 4
  5. 5 "FIELD""VALUE",
  6. 6
  7. 7 "FIELD""VALUE",
  8. 8
  9. 9 "FIELD""VALUE"
  10. 10
  11. 11}

5. 修改文档document


   
  1. 1和添加相同,并且_id存在

6. 删除文档document

1DELETE /索引名/type名/_id

7. 根据_id查询

1GET /索引名/type名/_id

8. 根据term查询


   
  1. 1POST /索引名/type名/_search
  2. 2
  3. 3{
  4. 4
  5. 5   "query": {
  6. 6
  7. 7     "term": {
  8. 8
  9. 9       "FIELD""VALUE"
  10. 10
  11. 11    }
  12. 12
  13. 13  }
  14. 14
  15. 15}

9. 根据query_string查询


   
  1. 1POST /索引名/type名/_search
  2. 2
  3. 3{
  4. 4
  5. 5   "query": {
  6. 6
  7. 7     "query_string": {
  8. 8
  9. 9     "default_field""FIELD",
  10. 10
  11. 11     "query""this AND that OR thus"
  12. 12
  13. 13    }
  14. 14
  15. 15  }
  16. 16
  17. 17}

IK分词器

查看分词效果


   
  1. 1GET /_analyze
  2. 2
  3. 3{
  4. 4
  5. 5   "analyzer""standard",
  6. 6
  7. 7   "text": "VALUE"
  8. 8
  9. 9}

集成IK分词器

  1. 下载IK分词器压缩包并解压缩

  2. 把其中elasticsearch文件夹改名ik-analyzer

  3. ik-analyzer文件夹放置在elasticsearch目录的plugins文件夹

  4. 重启elasticsearch服务器

  5. 试分词器效果,把analyzer的值改成ik_smart 或 ik_max_word

Elasticsearch集群

这里ES集群相当简单,它不像solr需要一个注册中心,其实玩过分布式童鞋都知道,玩集群无非多开几个实例并用一个或多个注册中心管理起来。而ES集群模式使用一个 P2P类型(使用 gossip 协议)的分布式系统,说白了就是一个广播分布式系统。所以配置起来比外带注册中心简单。

1. cluster(集群)

一个集群就是由一个或多个节点组织在一起,它们共同持有整个的数据,并一起提供索引和搜索功能。一个集群由一个唯一的名字标识,这个名字默认就是“elasticsearch”。这个名字是重要的,因为一个节点只能通过指定某个集群的名字,来加入这个集群。

2. node(节点)

就是一个集群的服务器

3. shards&replicas(分片&备份)

准备多台ES服务器,修改elasticsearch-cluster\config\elasticsearch.yml配置文件


   
  1. 1 #节点n的配置信息:
  2. 2
  3. 3 #集群名称,保证唯一
  4. 4
  5. 5cluster.name: elasticsearch
  6. 6
  7. 7 #节点名称,必须不一样
  8. 8
  9. 9node.name: node -1
  10. 10
  11. 11 #必须为本机的ip地址
  12. 12
  13. 13network.host:  127.0 .0 .1
  14. 14
  15. 15 #服务端口号,在同一机器下必须不一样
  16. 16
  17. 17http.port:  9200
  18. 18
  19. 19 #集群间通信端口号,在同一机器下必须不一样
  20. 20
  21. 21transport.tcp.port:  9300
  22. 22
  23. 23 #设置集群自动发现机器ip集合
  24. 24
  25. 25discovery.zen.ping.unicast.hosts: [ "127.0.0.1:9300", "127.0.0.1:9301", "127.0.0.1:9302"]

JAVA客户端

7.1 创建Maven工程,导入坐标


   
  1. 1<dependencies>
  2. 2
  3. 3    <dependency>
  4. 4
  5. 5        <groupId>org.elasticsearch</groupId>
  6. 6
  7. 7        <artifactId>elasticsearch</artifactId>
  8. 8
  9. 9        <version> 5.6 .10</version>
  10. 10
  11. 11    </dependency>
  12. 12
  13. 13    <dependency>
  14. 14
  15. 15        <groupId>org.elasticsearch.client</groupId>
  16. 16
  17. 17        <artifactId>transport</artifactId>
  18. 18
  19. 19        <version> 5.6 .10</version>
  20. 20
  21. 21    </dependency>
  22. 22
  23. 23    <dependency>
  24. 24
  25. 25        <groupId>org.apache.logging.log4j</groupId>
  26. 26
  27. 27        <artifactId>log4j-to-slf4j</artifactId>
  28. 28
  29. 29        <version> 2.9 .1</version>
  30. 30
  31. 31    </dependency>
  32. 32
  33. 33    <dependency>
  34. 34
  35. 35        <groupId>org.slf4j</groupId>
  36. 36
  37. 37        <artifactId>slf4j-api</artifactId>
  38. 38
  39. 39        <version> 1.7 .24</version>
  40. 40
  41. 41    </dependency>
  42. 42
  43. 43    <dependency>
  44. 44
  45. 45        <groupId>org.slf4j</groupId>
  46. 46
  47. 47        <artifactId>slf4j-simple</artifactId>
  48. 48
  49. 49        <version> 1.7 .21</version>
  50. 50
  51. 51    </dependency>
  52. 52
  53. 53    <dependency>
  54. 54
  55. 55        <groupId>log4j</groupId>
  56. 56
  57. 57        <artifactId>log4j</artifactId>
  58. 58
  59. 59        <version> 1.2 .12</version>
  60. 60
  61. 61    </dependency>
  62. 62
  63. 63    <dependency>
  64. 64
  65. 65        <groupId>junit</groupId>
  66. 66
  67. 67        <artifactId>junit</artifactId>
  68. 68
  69. 69        <version> 4.12</version>
  70. 70
  71. 71    </dependency>
  72. 72
  73. 73</dependencies>

7.2 创建索引库


   
  1. 1 public  class ElasticsearchClient {
  2. 2
  3. 3    @Test
  4. 4
  5. 5     public void createIndex() throws  Exception {
  6. 6
  7. 7 //        创建settings对象
  8. 8
  9. 9        Settings settings = Settings.builder()
  10. 10
  11. 11                .put( "cluster.name", "elasticsearch")
  12. 12
  13. 13                .build();
  14. 14
  15. 15 //        创建客户端对象
  16. 16
  17. 17        TransportClient client =  new PreBuiltTransportClient(settings);
  18. 18
  19. 19        client.addTransportAddress( new InetSocketTransportAddress(InetAddress.getByName( "127.0.0.1"), 9300));
  20. 20
  21. 21 //        创建索引库
  22. 22
  23. 23        client.admin().indices().prepareCreate( "index_hello").get();
  24. 24
  25. 25 //        关闭资源
  26. 26
  27. 27        client.close();
  28. 28
  29. 29    }
  30. 30
  31. 31}

7.3 设置映射


   
  1. 1 public  class ElasticsearchClient {
  2. 2
  3. 3    @Test
  4. 4
  5. 5     public void setMapping() throws  Exception {
  6. 6
  7. 7 //        创建settings对象
  8. 8
  9. 9        Settings settings = Settings.builder()
  10. 10
  11. 11                .put( "cluster.name", "elasticsearch")
  12. 12
  13. 13                .build();
  14. 14
  15. 15 //        创建客户端对象
  16. 16
  17. 17        TransportClient client =  new PreBuiltTransportClient(settings);
  18. 18
  19. 19        client.addTransportAddress( new InetSocketTransportAddress(InetAddress.getByName( "127.0.0.1"), 9300));
  20. 20
  21. 21 //        构建Mapping,RESTfull请求体
  22. 22
  23. 23        XContentBuilder builder = XContentFactory.jsonBuilder()
  24. 24
  25. 25                .startObject()
  26. 26
  27. 27                .startObject( "article")
  28. 28
  29. 29                .startObject( "properties")
  30. 30
  31. 31                    .startObject( "id")
  32. 32
  33. 33                    .field( "type", "long")
  34. 34
  35. 35                    .field( "store", true)
  36. 36
  37. 37                    .endObject()
  38. 38
  39. 39                    .startObject( "title")
  40. 40
  41. 41                    .field( "type", "text")
  42. 42
  43. 43                    .field( "store", true)
  44. 44
  45. 45                    .field( "analyzer", "ik_smart")
  46. 46
  47. 47                    .endObject()
  48. 48
  49. 49                    .startObject( "content")
  50. 50
  51. 51                    .field( "type", "text")
  52. 52
  53. 53                    .field( "store", true)
  54. 54
  55. 55                    .field( "analyzer", "ik_smart")
  56. 56
  57. 57                    .endObject()
  58. 58
  59. 59                .endObject()
  60. 60
  61. 61                .endObject()
  62. 62
  63. 63                .endObject();
  64. 64
  65. 65 //        使用客户端把mapping设置到索引库
  66. 66
  67. 67        client.admin().indices()
  68. 68
  69. 69                .preparePutMapping( "index_hello")
  70. 70
  71. 71                .setType( "article")
  72. 72
  73. 73                .setSource(builder)
  74. 74
  75. 75                .get();
  76. 76
  77. 77 //        关闭资源
  78. 78
  79. 79        client.close();
  80. 80
  81. 81    }
  82. 82
  83. 83}

7.4 添加文档


   
  1. 1 public  class ElasticsearchClient {
  2. 2
  3. 3    @Test
  4. 4
  5. 5     public void addDocument() throws  Exception {
  6. 6
  7. 7 //        创建settings对象
  8. 8
  9. 9        Settings settings = Settings.builder()
  10. 10
  11. 11                .put( "cluster.name", "elasticsearch")
  12. 12
  13. 13                .build();
  14. 14
  15. 15 //        创建客户端对象
  16. 16
  17. 17        TransportClient client =  new PreBuiltTransportClient(settings);
  18. 18
  19. 19        client.addTransportAddress( new InetSocketTransportAddress(InetAddress.getByName( "127.0.0.1"), 9300));
  20. 20
  21. 21        XContentBuilder builder = XContentFactory.jsonBuilder()
  22. 22
  23. 23                .startObject()
  24. 24
  25. 25                .field( "id", 1L)
  26. 26
  27. 27                .field( "title", "商务部:有序有力组织商贸企业复工复产")
  28. 28
  29. 29                .field( "content", "新华社北京2月23日电(记者陈炜伟、王雨萧)记者23日从商务部了解到,商务部印发《关于统筹做好生活必需品供应保障有关工作的通知》,要求各地商务主管部门在确保疫情防控安全的前提下,有序有力组织商贸企业复工复产。")
  30. 30
  31. 31                .endObject();
  32. 32
  33. 33 //        发送到服务器
  34. 34
  35. 35         client.prepareIndex( "index_hello", "article", "1")
  36. 36
  37. 37                .setSource(builder)
  38. 38
  39. 39                .get();
  40. 40
  41. 41 //        关闭资源
  42. 42
  43. 43        client.close();
  44. 44
  45. 45
  46. 46
  47. 47    }
  48. 48
  49. 49}

7.5 查询(核心功能)

  • 根据_Id查询

  • 根据Term查询

  • 据QueryString查询

  • 设置分页(在执行查询之前SearchResponse中方法setFrom和setSize)

  • 设置高亮


   
  1. 1 public  class SearchIndex {
  2. 2
  3. 3     private TransportClient client;
  4. 4
  5. 5    @Before
  6. 6
  7. 7     public void init()throws  Exception {
  8. 8
  9. 9 //        创建settings对象
  10. 10
  11. 11        Settings settings = Settings.builder()
  12. 12
  13. 13                .put( "cluster.name""elasticsearch")
  14. 14
  15. 15                .build();
  16. 16
  17. 17 //        创建客户端对象
  18. 18
  19. 19        client =  new PreBuiltTransportClient(settings);
  20. 20
  21. 21        client.addTransportAddress( new InetSocketTransportAddress(InetAddress.getByName( "127.0.0.1"),  9300));
  22. 22
  23. 23    }
  24. 24
  25. 25    @Test
  26. 26
  27. 27     public void searchById(){
  28. 28
  29. 29 //        创建查询对象
  30. 30
  31. 31        QueryBuilder queryBuilder = QueryBuilders.idsQuery().addIds( "1", "2");
  32. 32
  33. 33 //        执行查询
  34. 34
  35. 35        SearchResponse searchResponse = client.prepareSearch( "index_hello")
  36. 36
  37. 37                .setTypes( "article")
  38. 38
  39. 39                .setQuery(queryBuilder)
  40. 40
  41. 41                .get();
  42. 42
  43. 43 //        获取总记录数
  44. 44
  45. 45        SearchHits hits = searchResponse.getHits();
  46. 46
  47. 47        System.out.println( "总记录数:"+hits.getTotalHits());
  48. 48
  49. 49 //        结果列表
  50. 50
  51. 51        Iterator<SearchHit> iterator = hits.iterator();
  52. 52
  53. 53         while (iterator.hasNext()){
  54. 54
  55. 55            SearchHit next = iterator.next();
  56. 56
  57. 57            Map<String, Object> source = next.getSource();
  58. 58
  59. 59            System.out.println( "id:"+source.get( "id"));
  60. 60
  61. 61            System.out.println( "title:"+source.get( "title"));
  62. 62
  63. 63            System.out.println( "content:"+source.get( "content"));
  64. 64
  65. 65            System.out.println( "----------------------------------");
  66. 66
  67. 67        }
  68. 68
  69. 69
  70. 70
  71. 71    }
  72. 72
  73. 73    @Test
  74. 74
  75. 75     public void searchByTerm(){
  76. 76
  77. 77 //        创建查询对象
  78. 78
  79. 79        QueryBuilder queryBuilder = QueryBuilders.termQuery( "title", "复工");
  80. 80
  81. 81 //        执行查询
  82. 82
  83. 83        SearchResponse searchResponse = client.prepareSearch( "index_hello")
  84. 84
  85. 85                .setTypes( "article")
  86. 86
  87. 87                .setQuery(queryBuilder)
  88. 88
  89. 89                .get();
  90. 90
  91. 91 //        获取总记录数
  92. 92
  93. 93        SearchHits hits = searchResponse.getHits();
  94. 94
  95. 95        System.out.println( "总记录数:"+hits.getTotalHits());
  96. 96
  97. 97 //        结果列表
  98. 98
  99. 99        Iterator<SearchHit> iterator = hits.iterator();
  100. 100
  101. 101         while (iterator.hasNext()){
  102. 102
  103. 103            SearchHit next = iterator.next();
  104. 104
  105. 105            Map<String, Object> source = next.getSource();
  106. 106
  107. 107            System.out.println( "id:"+source.get( "id"));
  108. 108
  109. 109            System.out.println( "title:"+source.get( "title"));
  110. 110
  111. 111            System.out.println( "content:"+source.get( "content"));
  112. 112
  113. 113            System.out.println( "----------------------------------");
  114. 114
  115. 115        }
  116. 116
  117. 117
  118. 118
  119. 119    }
  120. 120
  121. 121    @Test
  122. 122
  123. 123     public void searchByQueryString(){
  124. 124
  125. 125 //        创建查询对象
  126. 126
  127. 127        QueryBuilder queryBuilder = QueryBuilders.queryStringQuery( "我家住在临安").defaultField( "title");
  128. 128
  129. 129 //        执行查询
  130. 130
  131. 131        SearchResponse searchResponse = client.prepareSearch( "index_hello")
  132. 132
  133. 133                .setTypes( "article")
  134. 134
  135. 135                .setQuery(queryBuilder)
  136. 136
  137. 137                .setFrom( 0)
  138. 138
  139. 139                .setSize( 3)
  140. 140
  141. 141                .highlighter( new HighlightBuilder().field( "title").preTags( "<em>").postTags( "</em>"))
  142. 142
  143. 143                .get();
  144. 144
  145. 145 //        获取总记录数
  146. 146
  147. 147        SearchHits hits = searchResponse.getHits();
  148. 148
  149. 149        System.out.println( "总记录数:"+hits.getTotalHits());
  150. 150
  151. 151 //        结果列表
  152. 152
  153. 153        Iterator<SearchHit> iterator = hits.iterator();
  154. 154
  155. 155         while (iterator.hasNext()){
  156. 156
  157. 157            SearchHit next = iterator.next();
  158. 158
  159. 159            Map<String, Object> source = next.getSource();
  160. 160
  161. 161            System.out.println( "id:"+source.get( "id"));
  162. 162
  163. 163            System.out.println( "title:"+source.get( "title"));
  164. 164
  165. 165            System.out.println( "content:"+source.get( "content"));
  166. 166
  167. 167            System.out.println( "----------------------------------");
  168. 168
  169. 169            HighlightField title = next.getHighlightFields().get( "title");
  170. 170
  171. 171            System.out.println(title.getFragments()[ 0]);
  172. 172
  173. 173        }
  174. 174
  175. 175
  176. 176
  177. 177    }
  178. 178
  179. 179    @After
  180. 180
  181. 181     public void close(){
  182. 182
  183. 183        client.close();
  184. 184
  185. 185    }
  186. 186
  187. 187}

Spring Data Elasticsearch

使用原始JAVA客户端操作ES非常复杂,Spring最擅长做整合对ES的操作将会大大简化,所以还是推荐使用Spring Data,原生的作为了解即可。

8.1 创建Maven工程,导入坐标


   
  1. 1    <dependencies>
  2. 2
  3. 3        <dependency>
  4. 4
  5. 5            <groupId>org.elasticsearch</groupId>
  6. 6
  7. 7            <artifactId>elasticsearch</artifactId>
  8. 8
  9. 9            <version> 5.6 .10</version>
  10. 10
  11. 11        </dependency>
  12. 12
  13. 13        <dependency>
  14. 14
  15. 15            <groupId>org.elasticsearch.client</groupId>
  16. 16
  17. 17            <artifactId>transport</artifactId>
  18. 18
  19. 19            <version> 5.6 .10</version>
  20. 20
  21. 21        </dependency>
  22. 22
  23. 23        <dependency>
  24. 24
  25. 25            <groupId>org.apache.logging.log4j</groupId>
  26. 26
  27. 27            <artifactId>log4j-to-slf4j</artifactId>
  28. 28
  29. 29            <version> 2.9 .1</version>
  30. 30
  31. 31        </dependency>
  32. 32
  33. 33        <dependency>
  34. 34
  35. 35            <groupId>org.slf4j</groupId>
  36. 36
  37. 37            <artifactId>slf4j-api</artifactId>
  38. 38
  39. 39            <version> 1.7 .24</version>
  40. 40
  41. 41        </dependency>
  42. 42
  43. 43        <dependency>
  44. 44
  45. 45            <groupId>org.slf4j</groupId>
  46. 46
  47. 47            <artifactId>slf4j-simple</artifactId>
  48. 48
  49. 49            <version> 1.7 .21</version>
  50. 50
  51. 51        </dependency>
  52. 52
  53. 53        <dependency>
  54. 54
  55. 55            <groupId>log4j</groupId>
  56. 56
  57. 57            <artifactId>log4j</artifactId>
  58. 58
  59. 59            <version> 1.2 .12</version>
  60. 60
  61. 61        </dependency>
  62. 62
  63. 63        <dependency>
  64. 64
  65. 65            <groupId>junit</groupId>
  66. 66
  67. 67            <artifactId>junit</artifactId>
  68. 68
  69. 69            <version> 4.12</version>
  70. 70
  71. 71        </dependency>
  72. 72
  73. 73        <dependency>
  74. 74
  75. 75            <groupId>com.fasterxml.jackson.core</groupId>
  76. 76
  77. 77            <artifactId>jackson-core</artifactId>
  78. 78
  79. 79            <version> 2.8 .1</version>
  80. 80
  81. 81        </dependency>
  82. 82
  83. 83        <dependency>
  84. 84
  85. 85            <groupId>com.fasterxml.jackson.core</groupId>
  86. 86
  87. 87            <artifactId>jackson-databind</artifactId>
  88. 88
  89. 89            <version> 2.8 .1</version>
  90. 90
  91. 91        </dependency>
  92. 92
  93. 93        <dependency>
  94. 94
  95. 95            <groupId>com.fasterxml.jackson.core</groupId>
  96. 96
  97. 97            <artifactId>jackson-annotations</artifactId>
  98. 98
  99. 99            <version> 2.8 .1</version>
  100. 100
  101. 101        </dependency>
  102. 102
  103. 103        <dependency>
  104. 104
  105. 105            <groupId>org.springframework.data</groupId>
  106. 106
  107. 107            <artifactId>spring-data-elasticsearch</artifactId>
  108. 108
  109. 109            <version> 3.0 .9.RELEASE</version>
  110. 110
  111. 111            <exclusions>
  112. 112
  113. 113                <exclusion>
  114. 114
  115. 115                    <groupId>org.elasticsearch.plugin</groupId>
  116. 116
  117. 117                    <artifactId>transport-netty4-client</artifactId>
  118. 118
  119. 119                </exclusion>
  120. 120
  121. 121            </exclusions>
  122. 122
  123. 123        </dependency>
  124. 124
  125. 125        <dependency>
  126. 126
  127. 127            <groupId>org.springframework</groupId>
  128. 128
  129. 129            <artifactId>spring-test</artifactId>
  130. 130
  131. 131            <version> 5.0 .8.RELEASE</version>
  132. 132
  133. 133            <scope>test</scope>
  134. 134
  135. 135        </dependency>
  136. 136
  137. 137
  138. 138
  139. 139    </dependencies>

8.2 添加配置文件


   
  1. 1 <?xml version= "1.0" encoding= "UTF-8" ?>
  2. 2
  3. 3<beans xmlns= "http://www.springframework.org/schema/beans"
  4. 4
  5. 5       xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
  6. 6
  7. 7       xmlns:context= "http://www.springframework.org/schema/context"
  8. 8
  9. 9       xmlns:elasticsearch= "http://www.springframework.org/schema/data/elasticsearch"
  10. 10
  11. 11       xsi:schemaLocation= "
  12. 12
  13. 13http://www.springframework.org/schema/beans
  14. 14
  15. 15http://www.springframework.org/schema/beans/spring-beans.xsd
  16. 16
  17. 17http://www.springframework.org/schema/context
  18. 18
  19. 19http://www.springframework.org/schema/context/spring-context.xsd
  20. 20
  21. 21http://www.springframework.org/schema/data/elasticsearch
  22. 22
  23. 23http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd
  24. 24
  25. 25">
  26. 26
  27. 27    <!-- 客户端对象 -->
  28. 28
  29. 29    <elasticsearch:transport-client id= "esClient" cluster-name= "elasticsearch" cluster-nodes= "127.0.0.1:9300"/>
  30. 30
  31. 31    <!-- 包扫描器 -->
  32. 32
  33. 33    <elasticsearch:repositories base-package= "com.itheima.es.repositories"/>
  34. 34
  35. 35    <!-- 模板对象 -->
  36. 36
  37. 37    <bean id= "elasticsearchTemplate"  class="org.springframework.data.elasticsearch.core.ElasticsearchTemplate">
  38. 38
  39. 39        <constructor-arg name="clientref="esClient"/>
  40. 40
  41. 41    </bean>
  42. 42
  43. 43</beans>

8.3 创建实体类,添加dao接口


   
  1. 1@Document(indexName =  "my_blog",type =  "article")
  2. 2
  3. 3 public  class Article {
  4. 4
  5. 5    @Id
  6. 6
  7. 7    @Field(type = FieldType.Long)
  8. 8
  9. 9     private Long id;
  10. 10
  11. 11    @Field(type = FieldType.Text,analyzer =  "ik_smart")
  12. 12
  13. 13     private String title;
  14. 14
  15. 15    @Field(type = FieldType.Text,analyzer =  "ik_smart")
  16. 16
  17. 17     private String content;
  18. 18
  19. 19
  20. 20
  21. 21     public Article() {
  22. 22
  23. 23    }
  24. 24
  25. 25
  26. 26
  27. 27     public Article(Long id, String title, String content) {
  28. 28
  29. 29        this.id = id;
  30. 30
  31. 31        this.title = title;
  32. 32
  33. 33        this.content = content;
  34. 34
  35. 35    }
  36. 36
  37. 37
  38. 38
  39. 39     public Long getId() {
  40. 40
  41. 41         return id;
  42. 42
  43. 43    }
  44. 44
  45. 45
  46. 46
  47. 47     public void setId(Long id) {
  48. 48
  49. 49        this.id = id;
  50. 50
  51. 51    }
  52. 52
  53. 53
  54. 54
  55. 55     public String getTitle() {
  56. 56
  57. 57         return title;
  58. 58
  59. 59    }
  60. 60
  61. 61
  62. 62
  63. 63     public void setTitle(String title) {
  64. 64
  65. 65        this.title = title;
  66. 66
  67. 67    }
  68. 68
  69. 69
  70. 70
  71. 71     public String getContent() {
  72. 72
  73. 73         return content;
  74. 74
  75. 75    }
  76. 76
  77. 77
  78. 78
  79. 79     public void setContent(String content) {
  80. 80
  81. 81        this.content = content;
  82. 82
  83. 83    }
  84. 84
  85. 85
  86. 86
  87. 87    @Override
  88. 88
  89. 89     public String toString() {
  90. 90
  91. 91         return  "Article{" +
  92. 92
  93. 93                 "id=" + id +
  94. 94
  95. 95                 ", title='" + title +  '\'' +
  96. 96
  97. 97                 ", content='" + content +  '\'' +
  98. 98
  99. 99                 '}';
  100. 100
  101. 101    }
  102. 102
  103. 103}

   
  1. 1 public  interface ArticleRepository extends ElasticsearchRepository<Article,Long{
  2. 2
  3. 3}

8.4 索引映射和文档增删改查


   
  1. 1@RunWith(SpringRunner.class)
  2. 2
  3. 3@ContextConfiguration( "classpath:applicationContext.xml")
  4. 4
  5. 5 public  class ESTest {
  6. 6
  7. 7    @Autowired
  8. 8
  9. 9     private ArticleRepository articleRepository;
  10. 10
  11. 11    @Autowired
  12. 12
  13. 13     private ElasticsearchTemplate template;
  14. 14
  15. 15    @Test
  16. 16
  17. 17     public void createIndex(){
  18. 18
  19. 19 //        创建索引并配置映射关系
  20. 20
  21. 21        template.createIndex(Article.class);
  22. 22
  23. 23 //        配置映射
  24. 24
  25. 25 //        template.putMapping(Article.class);
  26. 26
  27. 27    }
  28. 28
  29. 29    @Test
  30. 30
  31. 31     public void addDocumentAndUpdateDocument(){
  32. 32
  33. 33        Article article =  new Article( 2L, "时政新闻眼丨在一场罕见的电视电话会上,习近平这样动员战“疫”", "2月23日,农历二月初一。一场特别的会议在人民大会堂召开,分会场一直设到了县、团。中国正在打一场疫情防控的人民战争、总体战、阻击战。怎样分析这场战争?目前打到了哪一步?如何全面打赢?亲自指挥这场战争的习近平在这场“战时会议”上从容作答。");
  34. 34
  35. 35 //        添加文档
  36. 36
  37. 37        articleRepository.save(article);
  38. 38
  39. 39    }
  40. 40
  41. 41    @Test
  42. 42
  43. 43     public void delDocument(){
  44. 44
  45. 45 //        根据Id删除
  46. 46
  47. 47        articleRepository.deleteById( 1L);
  48. 48
  49. 49 //        全部删除
  50. 50
  51. 51 //        articleRepository.deleteAll();
  52. 52
  53. 53    }
  54. 54
  55. 55    @Test
  56. 56
  57. 57     public void findAll(){
  58. 58
  59. 59        Iterable<Article> all = articleRepository.findAll();
  60. 60
  61. 61        all. forEach(a-> System.out.println(a));
  62. 62
  63. 63    }
  64. 64
  65. 65    @Test
  66. 66
  67. 67     public void findById(){
  68. 68
  69. 69        Optional<Article> optional = articleRepository.findById( 2L);
  70. 70
  71. 71        System.out.println(optional.get());
  72. 72
  73. 73    }
  74. 74
  75. 75}

8.5 自定义查询

在接口中定义自定义查询,使用IDEA会有提示这里就不做介绍

8.6 原始查询条件查询


   
  1. 1 @Test
  2. 2
  3. 3     public void nativeSearch(){
  4. 4
  5. 5        NativeSearchQuery query =  new NativeSearchQueryBuilder()
  6. 6
  7. 7                .withQuery(
  8. 8
  9. 9                QueryBuilders.queryStringQuery( "测试一个查询")
  10. 10
  11. 11                .defaultField( "title")
  12. 12
  13. 13                ).withPageable(PageRequest.of( 0, 15))
  14. 14
  15. 15                .build();
  16. 16
  17. 17        AggregatedPage<Article> articles = template.queryForPage(query, Article.class);
  18. 18
  19. 19        articles. forEach(a-> System.out.println(a));
  20. 20
  21. 21    }

到此ES学习已经够项目上使用了,所以学了这门技术就不要让他在你的大脑吃灰,赶紧应用到你们的项目中,最后祝大家技术越学越NB!

附 字段属性

字段属性详解

type

Elasticsearch中支持的数据类型非常丰富:

我们说几个关键的:

  • String类型,又分两种:

    • text:可分词,不可参与聚合

    • keyword:不可分词,数据会作为完整字段进行匹配,可以参与聚合

  • Numerical:数值类型,分两类

    • 基本数据类型:long、interger、short、byte、double、float、half_float

    • 浮点数的高精度类型:scaled_float

      • 需要指定一个精度因子,比如10或100。elasticsearch会把真实值乘以这个因子后存储,取出时再还原。

  • Date:日期类型

elasticsearch可以对日期格式化为字符串存储,但是建议我们存储为毫秒值,存储为long,节省空间。

index

index影响字段的索引情况。

  • true:字段会被索引,则可以用来进行搜索。默认值就是true

  • false:字段不会被索引,不能用来搜索

index的默认值就是true,也就是说你不进行任何配置,所有字段都会被索引。

但是有些字段是我们不希望被索引的,比如商品的图片信息,就需要手动设置index为false。

store

是否将数据进行额外存储。

在学习lucene和solr时,我们知道如果一个字段的store设置为false,那么在文档列表中就不会有这个字段的值,用户的搜索结果中不会显示出来。

但是在Elasticsearch中,即便store设置为false,也可以搜索到结果。

原因是Elasticsearch在创建文档索引时,会将文档中的原始数据备份,保存到一个叫做_source的属性中。而且我们可以通过过滤_source来选择哪些要显示,哪些不显示。

而如果设置store为true,就会在_source以外额外存储一份数据,多余,因此一般我们都会将store设置为false,事实上,store的默认值就是false。

boost

激励因子,这个与lucene中一样

其它的不再一一讲解,用的不多,大家参考官方文档:

原文链接:

https://blog.csdn.net/mr_xinchen/article/details/104231377

【End】

在全民抗疫的特殊时期下,在人员复杂、流动量大地方的出入口处都设置了无接触式无感红外人体测温系统

在这次疫情防控中,无感人体测温系统发挥了怎样的作用高精准的无感人体测温系统的核心技术武器是什么?对于开发者们来说,大家应该了解哪些技术

今晚7点多场景疫情防控:解读云边端联动下的全栈 AI 技术应用

推荐阅读 

微信回应钉钉健康码无法访问;谷歌取消年度 I/O 开发者大会;微软公布 Visual Studio 最新路线图 | 极客头条

这项标准,支付宝干成了!中国将有更多主导权!

6个步骤,告诉你如何用树莓派和机器学习DIY一个车牌识别器!(附详细分析)

血亏 1.5 亿元!微盟耗时 145 个小时弥补删库

什么是 CD 管道?一文告诉你如何借助Kubernetes、Ansible和Jenkins创建CD管道!

智能合约初探:概念与演变

你点的每一个在看,我认真当成了喜欢


转载:https://blog.csdn.net/csdnnews/article/details/104666931
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场