ElasticSearch

本文详细介绍了ElasticSearch的环境搭建,包括Java、ES的安装,配置远程访问,并展示了如何使用Kibana进行基本操作。此外,还探讨了Java API集成,Spring Boot整合,以及集成中文分词器IK的过程。对于ES集群搭建,包括多节点配置和数据迁移也进行了讲解。最后,提出了深度分页的解决方案。
摘要由CSDN通过智能技术生成

前言

apache lucene
全文检索的工具包
索引:提供查询效率
	数据库索引:
		主键索引、唯一索引(unique)、复合索引(对数据库中的多个字段创建一个索引)、普通索引等

		create index 索引名 on table (column1,column2)

全文检索;类似于使用字典过程
	对数据预先构建索引,在查找的时通过索引匹配数据的过程就称为全文检索

	创建索引:
		1. 准备数据    北京欢迎您
		2. 数据分析(分词器 IK) 北京 | 欢迎 | 您
		3. 建立索引 
	检索索引:
		1. 准备检索关键词  北京
		2. 数据分析        北京
		3. 匹配索引        匹配成功
		4. 返回结果

	倒排序索引(反向索引):通过索引匹配数据

ElasticSearch 基于Lucene的搜索服务

Restful Web
表现层状态转换
传统web应用:http://localhost:8080/资源信息 login.html

restful api:
	请求地址:http://localhost:8080/user/1  
	请求方式:
		GET   {"id":1,"name":"zs"}
		DELETE {"result":true}
		POST 新增/更新
		PUT  更新

NOSQL:
Not Only SQL
四大分类
k v:Redis(持久化)、Memcached(基于内存存储)
document:类似于(JSON数据格式)
MongoDB、ElasticSearch
{“id”:1,“name”:“zs”}
column: HBase(百亿行,百万列)
图形:neo4j

ElasticSearch应用场景:
1. 全文检索
2. NOSQL
3. 数据分析平台(ELK)

ES核心概念:

  1. NRT —> near real time
    2. Cluster
    3. Node
    4. Index —> Database
    5. Type —> Table
    6. Document —> Row
    7. hard/replicas
    主分片: index中的部分数据集(创建一个索引默认创建5个主分片)
    复制分片: 主分片的数据备份(在主分片不同的物理节点中)
    8. mapping
    type类型的结构

ElasticSearch

一.环境搭建

  1. 准备

    • CentOS(版本需大于 7 如: CentOS-7-x86_64-Minimal-1804.iso )

    • Java(版本需大于 1.8 如: jdk-8u181-linux-x64.rpm )

    • ES安装包(如: elasticsearch-6.4.0.tar.gz )

    • 修改网卡

      vi /etc/sysconfig/network-scripts/ifcfg-ens33

      #修改为开机自动分配网卡
      ONBOOT=YES

      #或者修改为静态ip
      BOOYPROTO=static
      ONBOOT=yes
      #添加
      IPADDR=192.168.47.152(ip地址)
      NETMASK=255.255.255.0
      GATEWAY=192.168.47.2(虚拟机网段)
      DNS1=119.29.29.29
      DNS2=182.254.116.116

      
      
    • 重启网卡服务

      systemctl restart network

      
      
    • 关闭防火墙

      systemctl stop firewalld (centos6 : service iptables stop)
      systemctl disable firewalld (centos6 : chkconfig iptables off)

    • 查看ip

      ip a

  2. 安装java

    rpm -ivh jdk-8u181-linux-x64.rpm

    配置环境变量(可不用)

    vi /etc/profile

    export JAVA_HOME=/usr/java/latest
    export CLASSPATH=.
    export PATH= P A T H : PATH: PATH:JAVA_HOME/bin

    更新资源

    source /etc/profile

    
    
  3. 安装ES

    tar -zxvf elasticsearch-6.4.0.tar.gz -C /usr/

    
    
  4. 启动ES服务

    [root@bogon bin]# ./elasticsearch

    
    ==ES不允许通过ROOT用户启动==
    
    解决方案:
    
    - 创建普通用户,修改目录所属
    
    
      # groupadd es
      # useradd -g es es
      # chown -R es:es /usr/elasticsearch-6.4.0/
     
    
    - 切换用户
    
    
      su es
    
    • 启动
  5. 测试

    curl -X GET localhost:9200

    {
    “name” : “OC03Lum”,
    “cluster_name” : “elasticsearch”,
    “cluster_uuid” : “S0V8yt6KTaWZyKaZhDSBuA”,
    “version” : {
    “number” : “6.4.0”,
    “build_flavor” : “default”,
    “build_type” : “tar”,
    “build_hash” : “595516e”,
    “build_date” : “2018-08-17T23:18:47.308994Z”,
    “build_snapshot” : false,
    “lucene_version” : “7.4.0”,
    “minimum_wire_compatibility_version” : “5.6.0”,
    “minimum_index_compatibility_version” : “5.0.0”
    },
    “tagline” : “You Know, for Search”
    }

    
    
  6. 配置远程访问

    vim config/elasticsearch.yml

    显示行号
    :set nu

    51 # ---------------------------------- Network -----------------------------------
    52 #
    53 # Set the bind address to a specific IP (IPv4 or IPv6):
    54 #
    55 network.host: 192.168.30.135
    56 #
    57 # Set a custom port for HTTP:
    58 #
    59 #http.port: 9200
    60 #
    61 # For more information, consult the network module documentation.
    62 #
    63 # --------------------------------- Discovery ----------------------------------

    
    
  7. 重新启动ES服务,出现异常

    解决方案:切换到root用户修改配置文件

    vi /etc/security/limits.conf

    添加以下内容

    • soft nofile 65536
    • hard nofile 131072
    • soft nproc 2048
    • hard nproc 4096

    vi /etc/sysctl.conf

    添加以下内容

    vm.max_map_count=655360

    测试配置是否成功

    sysctl -p

    vm.max_map_count = 655360

    重启虚拟机
    reboot

    
    
  8. 测试访问

    192.168.30.135:9200

    
    
    

二.安装Kibana

Kibana是一个针对Elasticsearch的开源数据分析及可视化平台,用来搜索、查看交互存储在Elasticsearch索引中的数

据。使用Kibana,可以通过各种图表进行高级数据分析及展示。

Kibana让海量数据更容易理解。它操作简单,基于浏览器的用户界面可以快速创建仪表板(dashboard)实时显示

Elasticsearch查询动态。
设置Kibana非常简单。无需编码或者额外的基础架构,几分钟内就可以完成Kibana安装并启动Elasticsearch索引监
测。

  1. 安装配置

    # tar -zxvf kibana-6.4.0-linux-x86_64.tar.gz -C /usr
    # cd /usr/kibana-6.4.0-linux-x86_64/
    
    修改配置文件
    # vi config/kibana.yml
    
    # To allow connections from remote users, set this parameter to a non-loopback address.
    第七行 server.host: "192.168.23.141"
    # The URL of the Elasticsearch instance to use for all your queries.
    第28行 elasticsearch.url: "http://192.168.23.141:9200"
    
    启动服务
    [root@localhost kibana-6.4.0-linux-x86_64]# bin/kibana
    
  2. 启动测试

    "http://192.168.30.135:5601"
    

三.使用Kibana实现基本的增删改查

①查看集群
  • 查看集群健康信息

    GET /_cat/health?v

    集群状态(status)

    • Green(正常)
    • Yellow(正常,但是一些副本还没有分配)
    • Red(非正常)

    可以使用 GET /_cat/health?help 查看每个操作返回结果字段的意义

在这里插入图片描述

  • 查看集群中节点信息

    GET /_cat/nodes?v

  • 查看集群中的索引信息

    GET /_cat/indices?v

    简化写法

    GET /_cat/indices?v&h=health,status

②索引操作
  • 创建索引

    创建索引

    PUT /baizhi

    #! Deprecation: the default number of shards will change from [5] to [1] in 7.0.0; if you wish to continue using the default of [5] shards, you must manage this on the create index request or with an index template
    {
    “acknowledged”: true,
    “shards_acknowledged”: true,
    “index”: “baizhi”
    }

    在这里插入图片描述

  • 删除索引

    删除索引

    DELETE baizhi

  • 创建类型Mapping

    PUT /baizhi # 创建index(baizhi)并添加类型mapping(_doc)
    {
    “mappings”: { # 类比数据库中的表结构
    “_doc”: { # 类比数据库中的表名 可以更改 例如:user
    “properties”: {
    “title”: { “type”: “text” },
    “name”: { “type”: “text” },
    “age”: { “type”: “integer” },
    “created”: {
    “type”: “date”,
    “format”: “strict_date_optional_time||epoch_millis”
    }
    }
    }
    }
    }

    或者

    POST /baizhi/user # 创建index(baizhi)后,在指定index中添加类型mapping(user)
    {
    “user”: {
    “properties”: {
    “id”: { “type”: “text” },
    “name”: { “type”: “text” },
    “age”: { “type”: “integer” },
    “created”: {
    “type”: “date”,
    “format”: “strict_date_optional_time||epoch_millis”
    }
    }
    }
    }

    
    
  • 查看类型mapping

    语法:GET /索引名/_mapping/类型名

    GET /baizhi/_mapping/user

    结果

    {
    “baizhi”: {
    “mappings”: {
    “user”: {
    “properties”: {
    “created”: {“type”: “date”},
    “name”: {“type”: “text”},
    “title”: {“type”: “text”}
    }
    }
    }
    }
    }

    
    
③文档操作
  • 新增单个文档

    指定id

    PUT /baizhi/user/1
    {
    “title”:“haha”,
    “name”:“zhang3”,
    “created”:“2019-02-01”
    }

    结果

    {
    “_index”: “baizhi”,
    “_type”: “user”,
    “_id”: “1”,
    “_version”: 1,
    “result”: “created”,
    “_shards”: {
    “total”: 2,
    “successful”: 1,
    “failed”: 0
    },
    “_seq_no”: 0,
    “_primary_term”: 1
    }

    不指定id

    POST /baizhi/user
    {
    “title”:“hehe2”,
    “name”:“li4”,
    “created”:“2019-02-02”
    }

    结果

    {
    “_index”: “baizhi”,
    “_type”: “user”,
    “_id”: “PSjOSGkBdYhmP7fj_ARO”,
    “_version”: 1,
    “result”: “created”,
    “_shards”: {
    “total”: 2,
    “successful”: 1,
    “failed”: 0
    },
    “_seq_no”: 0,
    “_primary_term”: 1
    }

    
    
  • 查询单个文档

    GET /baizhi/user/1

    结果

    {
    “_index”: “baizhi”,
    “_type”: “user”,
    “_id”: “1”,
    “_version”: 1,
    “found”: true,
    “_source”: {
    “title”: “haha”,
    “name”: “zhang3”,
    “created”: “2019-02-01”
    }
    }

    
    
  • 修改单个文档

    PUT /baizhi/user/1
    {
    “name”:“zhang33333333”
    }

    结果

    {
    “_index”: “baizhi”,
    “_type”: “user”,
    “_id”: “1”,
    “_version”: 2,
    “result”: “updated”,
    “_shards”: {
    “total”: 2,
    “successful”: 1,
    “failed”: 0
    },
    “_seq_no”: 1,
    “_primary_term”: 1
    }

    查询结果

    {
    “_index”: “baizhi”,
    “_type”: “user”,
    “_id”: “1”,
    “_version”: 2,
    “found”: true,
    “_source”: {
    “name”: “zhang33333333” #只出现修改的数据
    }
    }

    
    
  • 删除单个文档

    DELETE /baizhi/user/1

    结果

    {
    “_index”: “baizhi”,
    “_type”: “user”,
    “_id”: “1”,
    “_version”: 3,
    “result”: “deleted”,
    “_shards”: {
    “total”: 2,
    “successful”: 1,
    “failed”: 0
    },
    “_seq_no”: 2,
    “_primary_term”: 1
    }

    
    
  • 批处理操作

    除了能够索引、更新和删除单个文档外,Elasticsearch还提供了使用 _bulk API 批量执行上述任何操作的能力。这个
    功能非常重要,因为它提供了一种非常有效的机制,可以以尽可能少的网络往返尽可能快地执行多个操作

    • 批量添加

    POST /baizhi/user/_bulk
    {“index”:{"_id":1}} # 指定id
    {“title”:“aa”,“name”:“aa”,“created”:“2019-02-02”}
    {“index”:{}} # 不指定id
    {“title”:“bb”,“name”:“bb”,“created”:“2019-02-02”}

    响应结果

    {
    “took”: 30,
    “errors”: false,
    “items”: [
    {
    “index”: {
    “_index”: “baizhi”,
    “_type”: “user”,
    “_id”: “1”,
    “_version”: 1,
    “result”: “created”,
    “_shards”: {
    “total”: 2,
    “successful”: 1,
    “failed”: 0
    },
    “_seq_no”: 3,
    “_primary_term”: 1,
    “status”: 201
    }
    },
    {
    “index”: {
    “_index”: “baizhi”,
    “_type”: “user”,
    “_id”: “PijdSGkBdYhmP7fj3gQf”,
    “_version”: 1,
    “result”: “created”,
    “_shards”: {
    “total”: 2,
    “successful”: 1,
    “failed”: 0
    },
    “_seq_no”: 4,
    “_primary_term”: 1,
    “status”: 201
    }
    }
    ]
    }

    • 批量操作

    POST /baizhi/user/_bulk
    {“update”:{"_id":“1”}}
    {“doc”:{“title”:“aaaaaa”}} # doc固定写法
    {“delete”:{"_id":“PijdSGkBdYhmP7fj3gQf”}}

    #结果
    {
    “took”: 23,
    “errors”: false,
    “items”: [
    {
    “update”: {
    “_index”: “baizhi”,
    “_type”: “user”,
    “_id”: “1”,
    “_version”: 2,
    “result”: “updated”,
    “_shards”: {
    “total”: 2,
    “successful”: 1,
    “failed”: 0
    },
    “_seq_no”: 5,
    “_primary_term”: 1,
    “status”: 200
    }
    },
    {
    “delete”: {
    “_index”: “baizhi”,
    “_type”: “user”,
    “_id”: “PijdSGkBdYhmP7fj3gQf”,
    “_version”: 2,
    “result”: “deleted”,
    “_shards”: {
    “total”: 2,
    “successful”: 1,
    “failed”: 0
    },
    “_seq_no”: 6,
    “_primary_term”: 1,
    “status”: 200
    }
    }
    ]
    }

四.深入搜索

搜索有两种方式:一种是通过 URL 参数进行搜索,另一种是通过 DSL(Request Body) 进行搜索

DSL:Domain Specified Language,特定领域语言
使用请求体可以让你的JSON数据以一种更加可读和更加富有展现力的方式发送。

导入测试数据
# 批量插入测试数据
POST /zpark/user/_bulk
{"index":{"_id":1}}
{"name":"zs","realname":"张三","age":18,"birthday":"2018-12-27","salary":1000.0,
 "address":"北京市昌平区沙阳路55号"}
{"index":{"_id":2}}
{"name":"ls","realname":"李四","age":20,"birthday":"2017-10-20","salary":5000.0,
 "address":"北京市朝阳区三里屯街道21号"}
{"index":{"_id":3}}
{"name":"ww","realname":"王五","age":25,"birthday":"2016-03-15","salary":4300.0,
 "address":"北京市海淀区中关村大街新中关商城2楼511室"}
{"index":{"_id":4}}
{"name":"zl","realname":"赵六","age":20,"birthday":"2003-04-19","salary":12300.0,
 "address":"北京市海淀区中关村软件园9号楼211室"}
{"index":{"_id":5}}
{"name":"tq","realname":"田七","age":35,"birthday":"2001-08-11","salary":1403.0,
 "address":"北京市海淀区西二旗地铁辉煌国际大厦负一楼"}
①查询

1.分页
2. 查所有

  1. 高亮(*)
  2. 匹配查询(match 分词)(*)
  3. Term(term 不会分词)(*)
  4. 数值范围(range lt gt lte gte)
  5. 前缀查询(prefix )
  6. 通配符查询(wildcard ? *)
  7. 模糊查询(fuzzy 首先进行精确匹配 再进行相关匹配)(*)
  8. 布尔查询(boolean 多条件 must must_not)
  • 查询所有并排序

    查看所有并按照年龄降序排列

    • URL实现

      GET /zpark/user/_search?q=*&sort=age:desc&pretty
      
    • DSL实现

      GET /zpark/user/_search
      {
          "query":{
              "match_all":{} # 查询所有
          },
          "sort":{
              "age":"desc"  # 按年龄倒序排列
          }
      }
      
  • 分页查询

    查询第2页的用户(每页显示2条)

    from:起始位置,从0开始

    size:查询数据的数量

    • URL实现

      GET /zpark/user/_search?q=*&sort=_id:asc&from=2&size=2
      
    • DSL实现

      GET /zpark/user/_search
      {
          "query":{
              "match_all":{} # 查询所有
          },
          "sort":{
              "_id":"asc"  # 按年龄倒序排列
          },
          "from":2, # 从(nowPage-1*pageSize检索
          "size":2  # 查 pageSize条
      }
      
  • 基于全文检索的查询(分析检索关键词 匹配索引库 返回结果)

    查询 address 在海淀区的所有用户,并高亮

    query查询时使用match,会将关键词进行分词

    • DSL实现

      GET /zpark/user/_search
      {
          "query": {
              "match": {
                  "address":"海淀区"
              }
          },
          "highlight": {
              "fields": { # 需要高亮的字段列表
                  "address": {} 
         	 	}
      	}
      }
      
  • 基于Term词元查询

    查询 name 是 zs 关键字的用户

    • URL实现

      GET /zpark/user/_search?q=name:zs
      
    • DSL实现

      term不会分词,查询关键字是一个整体

      GET /zpark/user/_search
      {
          "query":{
              "term": {
                  "name": {
                      "value": "zs"
                  }
              }
          }
      }
      
  • 基于范围查询

    查询年龄在 20~30 岁之间的用户

    • DSL实现

      GET /zpark/user/_search
      {
          "query": {
              "range": {
                  "age": {
                      "gte": 20,
                      "lte": 30
                  }
              }
          }
      }
      
  • 基于前缀(prefix)查询

    查询真实姓名以 李 开头的用户

    • DSL实现

      GET /zpark/user/_search
      {
          "query": {
              "prefix": {
                  "realname": {
                      "value": "李"
                  }
              }
          }
      }
      
  • 基于通配符(wildcard)的查询

    查询名字已 s 结尾的用户

    ? 匹配一个字符

    * 匹配0~n个字符

    • DSL实现

      GET /zpark/user/_search
      {
          "query": {
              "wildcard": {
                  "name": {
                      "value": "*s"
                  }
              }
          }
      }
      
  • 基于Ids的查询

    查询 id 为1,2,3的用户

    • DSL实现

      GET /zpark/user/_search
      {
          "query": {
              "ids": {
                  "values": [1,2,3]
              }
          }
      }
      
  • 基于Fuzzy的查询

    • DSL实现

      GET /zpark/user/_search
      {
          "query": {
              "fuzzy": {
                  "realname": {"value": "张"}
              }
          }
      }
      
  • 基于Boolean的查询(多条件查询)

    查询 age 在15-30岁之间并且 name 必须通配z*

    must :查询结果必须符合该查询条件(列表)。
    should :类似于or的查询条件。
    must_not :查询结果必须不符合查询条件(列表)。

    • DSL实现

      GET /zpark/user/_search
      {
          "query": {
              "bool": {
                  "must": [  #年龄在15~30岁之间并且必须名字通配z*
                      {
                          "range": {
                              "age": {
                                  "gte": 15,
                                  "lte": 30
                              }
                          }
                      },
                      {
                          "wildcard": {
                              "name": {
                                  "value": "z*"
                              }
                          }
                      }
                  ]"must_not": [  
                  {
               	   "regexp": {	# 正则查询 name必须不能以s结尾
               	  	 "name": ".*s"
             			 }
        			  }
         			]
      		}
      	}
      }
      
②过滤器

过滤器查询
query: 匹配结果 进行打分排名
filter: 结果匹配 true/false,会对结果进行缓存,会使用 bitset (位集合)
结论:首先使用过滤查询筛选符合条件的数据,再配合query查询进行精准匹配和相关度排序

1.term/terms

2.range

3.ids

4.exists

########################过滤器的使用######################
# 先过滤在查询   过滤查询运行时先执行过滤语句,后执行普通查询

#ranage filte 类型的过滤器
GET /zpark/user/_search
{
  "query": {
    "bool": {
      "must": [
        {"match_all": {}}
      ],
      "filter": {
        "range": {
          "age": {
            "gte": 20,
            "lte": 30
          }
        }
      }
    }
  }
}
# term 、 terms Filter 类型过滤器
GET /zpark/user/_search
{
  "query": {
    "bool": {
      "must": [
        {"match_all": {}}
      ],
      "filter": {
        "terms": {
          "name": [
            "zs",
            "ls"
          ]
        }
      }
    }
  }
}
#exists filter  exists 过滤指定字段没有值的文档
# 过滤地址不为空的数据
GET /zpark/user/_search
{
  "query": {
    "bool": {
      "must": [
        {"match_all": {}}
      ],
      "filter": {
        "exists": {
          "field": "address"
        }
      }
    }
  }
}
# (相反操作)
# 过滤地址不为空的数据
GET /zpark/user/_search
{
  "query": {
    "bool": {
      "must_not": [
        {
          "exists": {
            "field": "address"
          }
        }
      ]
    }
      
       
  }
}

#ids filter 
GET /zpark/user/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match_all": {}
        }
      ],
      "filter": {
        "ids": {
          "values": [
            "1",
            "2"
          ]
        }
      }
    }
  }
}
③聚合

聚合操作
1. 度量聚合(metric) 类似于 组函数
max\min\sum\avg\stats
2. 桶聚合(buket) 类似于 group by
range、terms、date range、histogram(interval 等分条件)、date histogram(日期等分)

###############聚合################################
# 度量聚合  类似于 组函数
# 平均值查询
POST /zpark/user/_search
{
  "aggs": {
    "age_svg": {
      "avg": {
        "field": "age"
      }
    }
  }
}
# 先过滤在统计
POST /zpark/user/_search
{
  "query": {
    "bool": {
      "filter": {
        "ids": {
          "values": [
            "1",
            "2"
          ]
        }
      }
    }
  },
  "aggs": {
    "agg_svg": {
      "avg": {
        "field": "age"
      }
    }
  }
}

# 先查询在统计
POST /zpark/user/_search
{
  "query": {
    "ids": {
      "values": [1,2]
    }
  },
  "aggs": {
    "age_avg": {
      "avg": {
        "field": "age"
      }
    }
  }
}

# 最大值查询
POST /zpark/user/_search
{
  "aggs": {
    "agg_max": {
      "max": {
        "field": "age"
      }
    }
  }
}

# 最小值
POST /zpark/user/_search
{
  "aggs": {
    "age_min": {
      "min": {
        "field": "age"
      }
    }
  }
}

# 求总和
POST /zpark/user/_search
{
  "query": {
    "bool": {
      "filter": {
        "ids": {
          "values": [
            1,2,3
          ]
        }
      }
    }
  },
  "aggs": {
    "agg_sum": {
      "sum": {
        "field": "age"
      }
    }
  }
}

#一个字段的统计全部信息
POST /zpark/user/_search
{
  "aggs": {
    "user_stats": {
      "stats": {
        "field": "age"
      }
    }
  }
}

#####################桶聚合###########################
# 相当于分组函数
# Range Aggregation  
#根据范围分组
POST /zpark/user/_search
{
  "aggs": {
    "age_range": {
      "range": {
        "field": "age",
        "ranges": [
          {
            "from": 10,
            "to": 20
          },
          {
            "from": 20,
            "to": 30
          },
          {
            "from": 30,
            "to": 40
          }
        ]
      }
    }
  }
}

GET /zpark/user/_search?q=*
#Terms Aggregation 自定义分组
POST /zpark/user/_search
{
  "aggs": {
    "age_count": {
      "terms": {
        "field": "age",
        "size": 5
      }
    }
  }
}

#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# date range aggregation
# 安装时间区域分组
GET /baizhi/aa/_search?q=*




POST /baizhi/aa/_search
{
  "aggs": {
    "date_counts": {
      "date_range": {
        "field": "birthday",
        "format": "yyyy-MM-dd", 
        "ranges": [
          {
            "from": "now/y-1y",
            "to": "now/y"
          }
        ]
      }
    }
  }
}
#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
#Histogram Aggregation 直方圆聚合
#根据年龄间隔(5岁)统计
POST /zpark/user/_search
{
  "aggs": {
    "age_counts": {
      "histogram": {
        "field": "age",
        "interval": 5
      }
    }
  }
}

#Date Histogram Aggregation
#按年统计用户
POST /baizhi/aa/_search
{
  "aggs": {
    "date_counts": {
      "date_histogram": {
        "field": "birthday",
        "interval": "year",
        "format": "yyyy-MM-dd"
      }
    }
  }
}


# 嵌套使用

#统计每年中用户的最高工资

POST /baizhi/aa/_search
{
  "aggs": {
    "date_counts": {
      "date_histogram": {
        "field": "birthday",
        "interval": "year",
        "format": "yyyy-MM-dd"
      },
      "aggs": {
        "salary_max": {
          "max": {
            "field": "salary"
          }
        }
      }
    }
  }
}

五、JAVA API 集成mavn

https://spring.io/projects/spring-data-elasticsearch#overview

Spring Data (spring开源组织提供的一套对主流存储系统的增删改查支持的开源项目)
ElasticSearch
1. 方式
restful api(通信方式:HTTP协议 + JSON)
es集群:9200端口
httpclient(类库 模拟发送http)
JAVA API
内置客户端
1. 节点客户端(无数据身份加入到es集群)
2. 传输客户端(操作请求的转发)
通信协议:ElasticSearch
端口:9300

查询方式
  • Restful API

基于http协议,使用JSON为数据交换格式,通过9200端口的与Elasticsearch进行通信

  • JAVA API( Spring Data ElasticSearch )

Spring Data ElasticSearch封装了与ES交互的实现细节,可以使系统开发者以Spring Data Repository 风格实现与ES的数据交互。Elasticsearch为Java用户提供了两种内置客户端:
节点客户端(node client): 节点客户端以无数据节点(none data node)身份加入集群,换言之,它自己不存储任何数据,但是它知道数据在集群中的具体位置,并且能够直接转发请求到对应的节点上。
传输客户端(Transport client): 这个更轻量的传输客户端能够发送请求到远程集群。它自己不加入集群,只是简单转发请求给集群中的节点。两个Java客户端都通过9300端口与集群交互,使用Elasticsearch传输协议(Elasticsearch Transport Protocol)。集群中的节点之间也通过9300端口进行通信。如果此端口未开放,你的节点将不能组成集群。

  • Spring Data ElasticSearch实践
    Maven依赖 (使用Spring Data ElasticSearch)
    
    <dependencies>
      <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-elasticsearch</artifactId>
        <version>3.1.3.RELEASE</version>
      </dependency>
      <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>5.1.3.RELEASE</version>
      </dependency>
      <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
      </dependency>
     </dependencies>
    
    准备配置文件
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:elasticesearch="http://www.springframework.org/schema/data/elasticsearch"
       xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/data/elasticsearch
    http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch.xsd">
      <!-- Spring data 自动扫描 repository接口,生成实现类 -->
      <elasticsearch:repositories base-package="com.baizhi.es.dao"></elasticsearch:repositories>
      <!-- ip:port换成具体的ip和端口,多个以逗号分隔 -->
      <elasticesearch:transport-client id="client" cluster-name="elasticsearch"
                      cluster-nodes="192.168.23.141:9300">
    </elasticesearch:transport-client>
     
      <!-- es操作对象-->
      <bean id="elasticsearchTemplate"
    class="org.springframework.data.elasticsearch.core.ElasticsearchTemplate">
        <constructor-arg name="client" ref="client"></constructor-arg>
      </bean>
      <!-- 自定义的Repository类用来实现特殊查询。。-->
      <bean id="customUserRepository" class="com.baizhi.es.dao.CustomUserRepositoryImpl">
      </bean>
    </beans>
    
    准备映射实体类
    package com.baizhi.entity;
    import org.springframework.data.annotation.Id;
    import org.springframework.data.annotation.PersistenceConstructor;
    import org.springframework.data.elasticsearch.annotations.Document;
    import java.util.Date;
    /**
    * @author gaozhy
    * @date 2018/12/28.17:05
    */
    // 文档注解 用于描述索引及其相关信息
    @Document(indexName = "zpark",type = "user")
    public class User {
      // 主键
      @Id
      private String id;
      private String name;
      private String realname;
      private Integer age;
      private Double salary;
      private Date birthday;
      private String address;
      public User() {
     }
      // 从es中恢复数据时使用的构造方法
      @PersistenceConstructor
      public User(String id, String name, String realname, Integer age, Double salary, Date
    birthday, String address) {
        this.id = id;
        this.name = name;
        this.realname = realname;
        this.age = age;
        this.salary = salary;
        this.birthday = birthday;
        this.address = address;
     }
    // 省略get/set toString方法 ......
    }
    
    spring data repository
    spring data elsaticsearch提供了三种构建查询模块的方式:
    • 基本的增删改查:继承spring data提供的接口就默认提供

    • 接口中声明方法:无需实现类,spring data根据方法名,自动生成实现类,方法名必须符合一定的规则(这里还扩展出一种忽略方法名,根据注解的方式查询)

    • 自定义repository:在实现类中注入elasticsearchTemplate,实现上面两种方式不易实现的查询(例如:聚合、分组、深度翻页等)

      上面的第一点和第二点只需要声明接口,无需实现类,spring data会扫描并生成实现类

#### **注意:repository接口和实现累的接口单独存放不要和dao包放一起,不然会被mybatis的扫描到创建代理类导致不能被工厂创建**
基础的repository接口:提供基本的增删改查和根据方法名的查询
package com.baizhi.es.dao;
import com.baizhi.entity.User;
import org.springframework.data.elasticsearch.annotations.Query;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import java.util.List;
/**
* 基础操作的es repository接口(定义的有通用的增删改查方法)
* 只需要继承 ElasticsearchRepository就可以
* @author gaozhy
* @date 2018/12/29.9:26
*/
public interface UserRepository extends ElasticsearchRepository<User,String> {
  /**
  * 一些方法只需按照固定书写接口就可以了
  * 根据年龄区间查询数据 并根据年龄降序排列
  */
  public List<User> findByAgeBetweenOrderByAgeDesc(int start,int end);
  /**
  * 查询真实姓名已“王”开头的数据
  */
  public List<User> findByRealnameStartingWith(String startStr);
  /**
  * 还可以通过Query注解自定义查询表达式
  */
  @Query("{\"bool\" : {\"must\" : {\"fuzzy\" : {\"name\" : \"?0\"}}}}")
  public List<User> findByNameLike(String name);
}
测试代码
package com.baizhi.es.test;
import com.baizhi.entity.User;
import com.baizhi.es.dao.UserRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.Date;
import java.util.List;
import java.util.Optional;
/**
* @author gaozhy
* @date 2018/12/29.9:30
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-es.xml")
public class UserRepositoryTest {
    @Autowired
  private UserRepository userRepository;
  /**
  * 查所有
  */
  @Test
  public void testQueryAll(){
    Iterable<User> users = userRepository.findAll();
    for (User user : users) {
      System.out.println(user);
   }
 }
  /**
  * 查询所有 并根据年龄倒序排列
  */
  @Test
  public void testQueryBySort(){
    Iterable<User> users = userRepository.findAll(Sort.by(Sort.Direction.DESC, "age"));
    for (User user : users) {
      System.out.println(user);
   }
 }
  /**
  * 根据id查询
  */
  @Test
  public void testQueryById(){
    Optional<User> user = userRepository.findById("1");
    System.out.println(user.get());
 }
  /**
  * 新增或者修改数据
  */
  @Test
  public void testAdd(){
    User user = userRepository.save(new User("6", "wb", "王八", 26, 10000D, new Date(), "河南
省郑州市二七区德化街南路33号"));
    System.out.println(user);
 }
  //==================================================================
  /**
  * 接口中声明方法查询:
  *  根据年龄区间查询数据 并根据年龄降序排列
  */
  @Test
  public void testQueryByRange(){
      List<User> users = userRepository.findByAgeBetweenOrderByAgeDesc(20, 28);
    users.forEach(user -> System.out.println(user));
 }
  /**
  * 接口中声明方法查询:
  *  查询真实姓名已“王”开头的数据
  *
  *  响应结果:
  *  User{id='6', name='wb', realname='王八', age=26, salary=10000.0, birthday=Sat Dec 29
14:38:39 CST 2018, address='河南省郑州市二七区德化街南路33号'}
     User{id='3', name='ww', realname='王五', age=25, salary=4300.0, birthday=Tue Mar 15
08:00:00 CST 2016, address='北京市海淀区中关村大街新中关商城2楼511室'}
  */
  @Test
  public void testQueryByPrefix(){
    List<User> users = userRepository.findByRealnameStartingWith("王");
    users.forEach(user -> System.out.println(user));
 }
 
  //==================================================================
  /**
  * 通过Query注解自定义查询表达式
  */
  @Test
  public void testQueryByNameLike(){
    List<User> users = userRepository.findByNameLike("zs");
    users.forEach(user -> System.out.println(user));
 }
}
自定义Repository接口:使用 elasticsearchTemplate 实现复杂查询
自定义 CustomUserRepository 接口不需要继承任何类自己实现
package com.baizhi.es.dao;
import com.baizhi.entity.User;
import java.util.List;
import java.util.Map;
/**
* @author gaozhy
* @date 2019/1/1.23:10
*/
public interface CustomUserRepository {
  public List<User> findByPageable(int nowPage,int pageSize);
  public List<User> findByFieldDesc(String field);
  public List<User> findByRealNameLikeAndHighLight(String realName);
  public List<User> findByNameWithTermFilter(String ...terms);
  public List<User> findByAgeWithRangeFilter(int start,int end);
  public Map findByNameStartingWithAndAggregations(String prefixName);
  /**
  * 嵌套查询:
  *
  * 先按年龄直方图(桶聚合)统计
  * 然后再统计区间内员工的最高工资(度量聚合)
  */
  public Map aggregationsWithHistogramAndMax();
  /**
  * 日期直方图(桶聚合)
  */
  public Map aggregationsWithDateHistogram();
}
自定义 CustomUserRepositoryImpl 实现类
package com.baizhi.es.dao;
import com.baizhi.entity.User;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.ResultsExtractor;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import static org.elasticsearch.index.query.QueryBuilders.*;
import org.springframework.stereotype.Repository;
/**
* @author gaozhy
* @date 2019/1/1.23:11
*/
@Repository
public class CustomUserRepositoryImpl implements CustomUserRepository {
    @Autowired
    private ElasticsearchTemplate template;
    /**
  * ====================================
  * {
  * "query": {
  * "match_all": {}
  * },
  * "from":1,   //从第几条开始  (从0开始)
  * "size":1   //大小
  * }
  * ====================================
  *
  * @param nowPage
  * @param pageSize
  * @return

    深度分页解决方案:
	PUT http://192.168.23.148:9200/my_index/_settings -d '{ "index" : { "max_result_window" : 500000}}'
	
 */
    @Override
    public List<User> findByPageable(int nowPage, int pageSize) {
        SearchQuery query = new NativeSearchQueryBuilder()
            .withQuery(matchAllQuery())
            .withPageable(new PageRequest((nowPage - 1) * pageSize, pageSize))
            .build();
        return template.queryForList(query, User.class);
    }
    /**
  * @param field
  * @return
  */
    @Override
    public List<User> findByFieldDesc(String field) {
        SearchQuery query = new NativeSearchQueryBuilder()
            .withQuery(matchAllQuery())
            .withSort(SortBuilders.fieldSort(field).order(SortOrder.DESC))
            .build();
        return template.queryForList(query, User.class);
    }
    /**
  * 高亮
   *
  * @param realName
  * @return
  */
    @Override
    public List<User> findByRealNameLikeAndHighLight(String realName) {
        // 创建搜索构造器
        SearchQuery query = new NativeSearchQueryBuilder()
            .withQuery(matchQuery("realname", realName))
            .withHighlightFields(new HighlightBuilder.Field("realname"))
            .build();
          // 获取查询结果
        AggregatedPage<User> users = template.queryForPage(query, User.class, newSearchResultMapper() {
                @Override
                public <T> AggregatedPage<T> mapResults(SearchResponse searchResponse, Class<T> aClass, Pageable pageable) {
                     ArrayList<User> users = new ArrayList<>();
                     SearchHits searchHits = searchResponse.getHits();
                     for (SearchHit searchHit : searchHits) {
                         if (searchHits.getHits().length <= 0) {
                                return null;
                            }
                  	 //  获取文档对象属性map集合    
              		 Map<String ,Object> map = searchHit.getSourceAsMap();
                         
              		// 将获取到的数据封装到对象中
            	    User user = new User();
                    user.setId(searchHit.getId());
                 // searchHit.getSourceAsMap().forEach((k, v) -> System.out.println(k + " " + v));
                    user.setName(map.get("name").toString());
                    user.setAddress(map.get("address").toString());
                    user.setAge(Integer.parseInt(map.get("age").toString()));
                    user.setBirthday(new Date(Long.parseLong(map.get("birthday").toString())));
                    user.setSalary(Double.parseDouble(map.get("salary").toString()));
                    // 获取高亮的数据         
                    String realname =searchHit.getHighlightFields().get("realname").fragments()[0].toString();
                    // 将高亮信息替换原本信息封装到对象中        
                    user.setRealname(realname);
                    // 添加到集合中
                    users.add(user);
                    }
         		return new AggregatedPageImpl<T>((List<T>) users);
               }
         });
        return users.getContent();
    }
    
    @Override
    public List<User> findByNameWithTermFilter(String... name) {
        SearchQuery query = new NativeSearchQueryBuilder()
            .withQuery(matchAllQuery())
            .withFilter(termsQuery("name",name))
            .build();
        System.out.println(query.getFilter());
        return template.queryForList(query,User.class);
    }
    @Override
    public List<User> findByAgeWithRangeFilter(int start, int end) {
        SearchQuery query = new NativeSearchQueryBuilder()
            .withFilter(rangeQuery("age").gte(start).lte(end))
            .build();
        System.out.println(query.getQuery());
        System.out.println(query.getFilter());
        return template.queryForList(query,User.class);
    }
    @Override
    public Map<String, Aggregation> findByNameStartingWithAndAggregations(String prefixName) {
        SearchQuery query = new NativeSearchQueryBuilder()
            .withQuery(prefixQuery("name",prefixName))
            // result为度量聚合结果的别名
            .addAggregation(AggregationBuilders.avg("result").field("age"))
            .build();
        Aggregations aggregations = template.query(query, new ResultsExtractor<Aggregations>(){
            @Override
           public Aggregations extract(SearchResponse searchResponse) {
                Aggregations aggregations = searchResponse.getAggregations();
                return aggregations;
            }
         });
        Map<String, Aggregation> map = aggregations.getAsMap();
        return map;
    }
    
    @Override
    public Map aggregationsWithHistogramAndMax() {
        SearchQuery query = new NativeSearchQueryBuilder()
            .addAggregation(AggregationBuilders.histogram("result").field("age").interval(5)
            .subAggregation(AggregationBuilders.max("max_salary").field("salary")))
            .build();
        Aggregations aggregations = template.query(query, new ResultsExtractor<Aggregations>(){
           @Override
           public Aggregations extract(SearchResponse searchResponse) {
           return searchResponse.getAggregations();
            }
       });
       return aggregations.getAsMap();
    }
    
    @Override
    public Map aggregationsWithDateHistogram() {
        SearchQuery query = new NativeSearchQueryBuilder()
            .addAggregation(AggregationBuilders.dateHistogram("result").field("birthday")
            .format("yyyy-MM-dd").dateHistogramInterval(DateHistogramInterval.YEAR))
            .build();
      Aggregations aggregations = template.query(query, new ResultsExtractor<Aggregations>(){
               @Override                                                                                                                        public Aggregations extract(SearchResponse searchResponse) {                                                                           return searchResponse.getAggregations();                                                                                    }
			});
         return aggregations.getAsMap();
  }
}
自定义 CustomUserRepositoryTest 测试类
package com.baizhi.es.test;
import com.baizhi.entity.User;
import com.baizhi.es.dao.CustomUserRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
import java.util.Map;
/**
* @author gaozhy
* @date 2019/1/1.23:26
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-es.xml")
public class CustomUserRepositoryTest {
  @Autowired
  private CustomUserRepository repository;
  @Test
  public void testQueryByPage(){
    List<User> users = repository.findByPageable(0, 2);
    users.forEach(user -> {
      System.out.println(user);
   });
 }
  @Test
  public void testQueryBySort(){
    List<User> users = repository.findByFieldDesc("_id");
    users.forEach(user -> {
        System.out.println(user);
   });
 }
  @Test
  public void testQueryByHighLight(){
    List<User> users = repository.findByRealNameLikeAndHighLight("王八");
    users.forEach(user -> {
      System.out.println(user);
   });
 }
  @Test
  public void testQueryByNameWithTermFilter(){
    List<User> users = repository.findByNameWithTermFilter("zs","ls");
    users.forEach(user -> {
      System.out.println(user);
   });
 }
  @Test
  public void testQueryByAgeWithRangeFilter(){
    List<User> users = repository.findByAgeWithRangeFilter(21,30);
    users.forEach(user -> {
      System.out.println(user);
   });
 }
  @Test
  public void testQueryByNameStartingWithAndAggregations(){
    Map map = repository.findByNameStartingWithAndAggregations("z");
    System.out.println(map.get("result"));
 }
  @Test
  public void testAggregationsWithHistogramAndMax(){
    Map map = repository.aggregationsWithHistogramAndMax();
    System.out.println(map.get("result"));
 }
  @Test
  public void testAggregationsWithDateHistogram(){
    Map map = repository.aggregationsWithDateHistogram();
    System.out.println(map.get("result"));
 }
}

六、Java Api集成springboot

springboot 的版本必须是2.0 以上版本

springboot依赖 (使用Spring Data ElasticSearch)
<!--elasticsearch集成springboot的依赖-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
		</dependency>
springboot配置文件
#配置节点端口
spring.data.elasticsearch.cluster-nodes=192.168.21.145:9300

其余相同和mavn

七、集成中文分词器IK

参考资料:https://github.com/medcl/elasticsearch-analysis-ik

安装

自动下载指令

./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.4.0/elasticsearch-analysis-ik-6.4.0.zip

[es@localhost root]$ cd /usr/elasticsearch-6.4.0/
[es@localhost elasticsearch-6.4.0]$ 

./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.4.0/elasticsearch-analysis-ik-6.4.0.zip

-> Downloading https://github.com/medcl/elasticsearch-analysis-
ik/releases/download/v6.4.0/elasticsearch-analysis-ik-6.4.0.zip
[=================================================] 100% 
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@   WARNING: plugin requires additional permissions   @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
* java.net.SocketPermission * connect,resolve
See http://docs.oracle.com/javase/8/docs/technotes/guides/security/permissions.html
for descriptions of what these permissions allow and the associated risks.
Continue with installation? [y/N]y
-> Installed analysis-ik
[es@localhost elasticsearch-6.4.0]$ ll plugins/
total 0
drwxr-xr-x. 2 es es 229 Jan  3 10:04 analysis-ik

# 重新启动es的服务使用ik
[root@localhost ~]# jps
2673 Elasticsearch
46151 Jps
40921 PluginCli
[root@localhost ~]# kill -9 2673
[root@localhost ~]# cd /usr/elasticsearch-6.4.0/
[root@localhost elasticsearch-6.4.0]# su es
[es@localhost elasticsearch-6.4.0]$ bin/elasticsearch
测试
创建测试索引
################古诗词##################

#DELETE /poem

PUT /poem
创建类型映射
POST /poem/poemDto/_mapping
{
  "properties": {
    "id":{"type":"text"},
    "poetId":{"type":"integer"},
    "poetName":{
      "type":"text",
      "analyzer": "ik_max_word",# 会将文本做最细粒度的拆分
      "search_analyzer": "ik_max_word"# 查询是使用细粒度查询
    },
    "poetityId":{"type":"integer"},
    "poetityTitle":{
      "type":"text",
      "analyzer": "ik_max_word",
      "search_analyzer": "ik_max_word"
    },
    "poetityContent":{
      "type":"text",
      "analyzer": "ik_max_word",
      "search_analyzer": "ik_max_word"
    }
  }
}


#查看全部索引
GET /poem/poemDto/_search?q=*
插入测试数据
POST /poem/poemDto/_bulk
{"index":{"id":1}}
{"poetId":1,
 "poetName":"李白",   
 "poetityId":1,
 "poetityTitle":"将敬酒" 
 "poetityContent":"人生得意须尽欢,莫使金樽空对月"
 }
{"index":{"id":2}}
{"poetId":1,
 "poetName":"杜普",   
 "poetityId":1,
 "poetityTitle":"绝句" 
 "poetityContent":"人生得意须尽欢,莫使金樽空对月"
 }
根据关键词高亮查询
GET /poem/poemDto/_search
{
 "query": {
  "match": {
   "poemName": "李白"
 }
},
 "highlight": {
  "fields": {"poemName": {}}
}
}
IK词典配置

先创建一个词典文件 mydict.dic

[root@localhost analysis-ik]# vim /usr/elasticsearch-6.4.0/config/analysis-
ik/IKAnalyzer.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
    <comment>IK Analyzer 扩展配置</comment>
    <!--用户可以在这里配置自己的扩展字典 -->
    <entry key="ext_dict">mydict.dic</entry>
    <!--用户可以在这里配置自己的扩展停止词字典-->
    <entry key="ext_stopwords"></entry>
    <!--用户可以在这里配置远程扩展字典 -->
    <!--<entry key="remote_ext_dict">location</entry>-->
    <!--用户可以在这里配置远程扩展停止词字典-->
    <!--<entry key="remote_ext_stopwords">http://xxx.com/xxx.dic</entry>-->
</properties>

八、es集群搭建

ES集群

a. 准备至少两台服务器
b. 修改核心配置文件
cluster.name: elasticsearch
	node.name: node-1
	network.host: 192.168.23.148
	discovery.zen.ping.unicast.hosts: ["192.168.23.148:9300","192.168.23.149:9300"]
	
#修改另外一台的文件
 # 可以将改好的文件复制到零一台中
[root@bogon config]# scp elasticsearch.yml root@192.168.23.149:/usr/elasticsearch-6.4.0/config/
c.将第二代的elasticsearch的data日志信息删除 和logs日志
[es@bogonelasticsearch]  rm  -f data/*
[es@bogonelasticsearch]  rm  -f logs/*
d. 请求新es服务的历史数据
ES集群和Spring Boot整合
a. 创建spring boot工程 并导入es的依赖
b. 修改配置文件
	spring.data.elasticsearch.cluster-nodes=192.168.23.148:9300,192.168.23.149:9300
c. spring boot工程入口类 加上注解
	@EnableElasticsearchRepositories(basePackages = "com.baizhi.dao.es")

d. 和之前将的一样

深度分页解决方案:

PUT http://192.168.23.148:9200/my_index/_settings -d '{ "index" : { "max_result_window" : 500000}}'
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值