一、安装
1、拉取镜像
docker pull elasticsearch:6.5.4
2、创建配置及数据目录
cd /home/frnt/service
mkdir es
cd es
mkdir config
mkdir data1
mkdir data2
mkdir data3
3、创建配置文件
cd config
vi es1.yml
------------------------------------------------------------------------------------------
cluster.name: elasticsearch-cluster
node.name: es-node1
network.bind_host: 0.0.0.0
network.publish_host: 0.0.0.0
http.port: 9200
transport.tcp.port: 9300
http.cors.enabled: true
http.cors.allow-origin: "*"
node.master: true
node.data: true
discovery.zen.ping.unicast.hosts: ["192.168.43.100:9300","192.168.43.100:9301","192.168.43.100:9302"]
discovery.zen.minimum_master_nodes: 2
vi es2.yml
------------------------------------------------------------------------------------------
cluster.name: elasticsearch-cluster
node.name: es-node2
network.bind_host: 0.0.0.0
network.publish_host: 0.0.0.0
http.port: 9201
transport.tcp.port: 9301
http.cors.enabled: true
http.cors.allow-origin: "*"
node.master: true
node.data: true
discovery.zen.ping.unicast.hosts: ["192.168.43.100:9300","192.168.43.100:9301","192.168.43.100:9302"]
discovery.zen.minimum_master_nodes: 2
vi es3.yml
------------------------------------------------------------------------------------------
cluster.name: elasticsearch-cluster
node.name: es-node3
network.bind_host: 0.0.0.0
network.publish_host: 0.0.0.0
http.port: 9202
transport.tcp.port: 9302
http.cors.enabled: true
http.cors.allow-origin: "*"
node.master: true
node.data: true
discovery.zen.ping.unicast.hosts: ["192.168.43.100:9300","192.168.43.100:9301","192.168.43.100:9302"]
discovery.zen.minimum_master_nodes: 2
4、调高jvm线程数限制
vi /etc/sysctl.conf
#添加
vm.max_map_count=655360
#执行生效
sysctl –p
5、启动集群
docker run -e ES_JAVA_OPTS="-Xms256m -Xmx256m" -d -p 9200:9200 -p 9300:9300 -v /home/frnt/service/es/config/es1.yml:/usr/share/elasticsearch/config/elasticsearch.yml -v /home/frnt/service/es/data1:/usr/share/elasticsearch/data --name es01 elasticsearch:6.5.4
docker run -e ES_JAVA_OPTS="-Xms256m -Xmx256m" -d -p 9201:9201 -p 9301:9301 -v /home/frnt/service/es/config/es2.yml:/usr/share/elasticsearch/config/elasticsearch.yml -v /home/frnt/service/es/data2:/usr/share/elasticsearch/data --name es02 elasticsearch:6.5.4
docker run -e ES_JAVA_OPTS="-Xms256m -Xmx256m" -d -p 9202:9202 -p 9302:9302 -v /home/frnt/service/es/config/es3.yml:/usr/share/elasticsearch/config/elasticsearch.yml -v /home/frnt/service/es/data3:/usr/share/elasticsearch/data --name es03 elasticsearch:6.5.4
6、安装elasticsearch-head
#拉取镜像
docker pull mobz/elasticsearch-head:5
#启动elasticsearch-head
docker run --name es-head -d -p 9100:9100 mobz/elasticsearch-head:5
- 注意:现在访问elasticsearch-head是不可以的,需要进入容器设置几处。
#进入容器
docker exec -it es-head /bin/bash
#编辑Gruntfile.js
-----------------------------------------------------------------------------
connect: {
server: {
options: {
hostname:'*',
port: 9100,
base: '.',
keepalive: true
}
}
}
cd _site
# 编辑app.js的base_uri,将 localhost 改成 主机IP(192.168.43.100)
------------------------------------------------------------------------------
this.base_uri = this.config.base_uri || this.prefs.get("app-base_uri") || "http://localhost:9200";
退出容器,重启即可访问:http://192.168.43.100:9100/
7、安装分词器
(1)下载IK分词器
(2)复制到容器plugins下
docker cp elasticsearch-analysis-ik-6.5.4.zip ES01:/usr/share/elasticsearch/plugins/
docker cp elasticsearch-analysis-ik-6.5.4.zip ES02:/usr/share/elasticsearch/plugins/
docker cp elasticsearch-analysis-ik-6.5.4.zip ES03:/usr/share/elasticsearch/plugins/
(3)解压
mkdir ik
mv elasticsearch-analysis-ik-6.5.4.zip ik/
unzip elasticsearch-analysis-ik-6.5.4.zip
rm -fr elasticsearch-analysis-ik-6.5.4.zip
(4)重启容器即可
docker restart es01
docker restart es02
docker restart es03
二、Springboot集成elasticsearch
以省市区县(area.json)数据为例进行CRUD操作。
1、pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2、vo
package com.example.demo.module;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
@Data
@Document(indexName = "area",type = "docs", shards = 3, replicas = 1)
public class AreaVo {
/**
* 区域ID
*/
@Id
private Integer areaId;
/**
* 区域名称
*/
@Field(type = FieldType.text, analyzer = "ik_max_word",searchAnalyzer="ik_smart")
private String areaName;
/**
* 父级ID
*/
@Field(type = FieldType.keyword)
private Integer parentId;
/**
* 地区级别(地区级别(1:省份province,2:市city,3:区县district,4:街道street)
*/
@Field(type = FieldType.keyword)
private Integer level;
/**
* 城市编码
*/
@Field(type = FieldType.keyword)
private String cityCode;
/**
* 邮编
*/
@Field(type = FieldType.keyword)
private String zipCode;
/**
* 简称
*/
@Field(type = FieldType.text, analyzer = "ik_max_word",searchAnalyzer="ik_smart")
private String shortName;
/**
* 拼音
*/
@Field(type = FieldType.text, analyzer = "ik_max_word",searchAnalyzer="ik_smart")
private String pinyin;
/**
* 全称
*/
@Field(type = FieldType.text, analyzer = "ik_max_word",searchAnalyzer="ik_smart")
private String mergerName;
}
3、ElasticsearchBaseService
package com.example.demo.module;
import org.springframework.data.domain.Page;
import java.util.List;
public interface ElasticsearchBaseService<T> {
List<T> list(int type, String fieldName, String query);
T save(T t);
Page<T> page(Integer pageNum, Integer pageSize, int type, String fieldName, String query);
void delete(T t);
}
4、ElasticsearchSearchService
package com.example.demo.module;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.WildcardQueryBuilder;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public abstract class ElasticsearchSearchService<T> implements ElasticsearchBaseService<T> {
protected abstract ElasticsearchRepository getBaseRepository();
/**
*
* @param type 类型 1:精确查询,2:模糊查询
* @param fieldName 查询的字段名称
* @param query 查询条件
* @return
*/
@Override
public List<T> list(int type, String fieldName, String query) {
if(type != 1 && type != 2){
throw new IllegalArgumentException("非法入参");
}
//模糊匹配
if(type == 2){
query=matchString(query);
}
WildcardQueryBuilder queryBuilder = QueryBuilders.wildcardQuery(fieldName, query);
Iterable<T> search = getBaseRepository().search(queryBuilder);
List<T> list=new ArrayList<>();
Iterator<T> iterator = search.iterator();
while (iterator.hasNext()){
list.add(iterator.next());
}
return list;
}
/**
* 添加索引(包含更新)
* @param t
* @return
*/
@Override
public T save(T t){
return (T) getBaseRepository().save(t);
}
/**
* 分页查询
* @param pageNum 起始页
* @param pageSize
* @param type 类型 1:精确查询,2:模糊查询
* @param fieldName 查询的字段名称
* @param query 查询条件
* @return
*/
@Override
public Page<T> page(Integer pageNum, Integer pageSize,int type,String fieldName, String query) {
if(type != 1 && type != 2){
throw new IllegalArgumentException("非法入参");
}
if(pageNum == null){
pageNum = 0;
}
if(pageSize == null){
pageSize=20;
}
//模糊匹配
if(type == 2){
query=matchString(query);
}
WildcardQueryBuilder queryBuilder = QueryBuilders.wildcardQuery(fieldName, query);
return getBaseRepository().search(queryBuilder, PageRequest.of(pageNum,pageSize));
}
/**
* 删除
* @param t
*/
@Override
public void delete(T t){
getBaseRepository().delete(t);
}
protected String matchString(String str){
return "*".concat(str).concat("*");
}
}
5、AreaRepository
package com.example.demo.module;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
public interface AreaRepository extends ElasticsearchRepository<AreaVo,Integer> {
}
6、AreaService
package com.example.demo.module;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Service;
@Service
public class AreaService extends ElasticsearchSearchService<AreaVo>{
@Autowired
private AreaRepository AreaRepository;
@Override
public ElasticsearchRepository getBaseRepository() {
return AreaRepository;
}
}
7、AreaController
package com.example.demo.module;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/area")
public class AreaController {
@Autowired
private AreaService areaService;
@RequestMapping("/list")
public List<AreaVo> list(@RequestParam("fieldName") String fieldName, @RequestParam("query") String query){
return areaService.list(2, fieldName, query);
}
@RequestMapping("/save")
public void save(@RequestBody AreaVo areaVo) {
areaService.save(areaVo);
}
@RequestMapping("/page")
public Page<AreaVo> page(@RequestParam("pageNum") Integer pageNum, @RequestParam("pageSize") Integer pageSize, @RequestParam("fieldName") String fieldName, @RequestParam("query") String query){
return areaService.page(pageNum, pageSize, 2, fieldName, query);
}
@RequestMapping("/delete")
public void delete(@RequestBody AreaVo areaVo) {
areaService.delete(areaVo);
}
}
8.area.json样例
{
"RECORDS": [
{
"area_id": "100000",
"area_name": "中国",
"parent_id": "0",
"short_name": "中国",
"level": "0",
"city_code": "",
"zip_code": "",
"merger_name": "中国",
"pinyin": "China"
},
{
"area_id": "110000",
"area_name": "北京",
"parent_id": "100000",
"short_name": "北京",
"level": "1",
"city_code": "",
"zip_code": "",
"merger_name": "北京",
"pinyin": "Beijing"
},
{
"area_id": "110100",
"area_name": "北京市",
"parent_id": "110000",
"short_name": "北京",
"level": "2",
"city_code": "010",
"zip_code": "100000",
"merger_name": "北京,北京市",
"pinyin": "Beijing"
},
{
"area_id": "110101",
"area_name": "东城区",
"parent_id": "110100",
"short_name": "东城",
"level": "3",
"city_code": "010",
"zip_code": "100010",
"merger_name": "北京,北京市,东城区",
"pinyin": "Dongcheng"
},
{
"area_id": "110102",
"area_name": "西城区",
"parent_id": "110100",
"short_name": "西城",
"level": "3",
"city_code": "010",
"zip_code": "100032",
"merger_name": "北京,北京市,西城区",
"pinyin": "Xicheng"
},
{
"area_id": "110105",
"area_name": "朝阳区",
"parent_id": "110100",
"short_name": "朝阳",
"level": "3",
"city_code": "010",
"zip_code": "100020",
"merger_name": "北京,北京市,朝阳区",
"pinyin": "Chaoyang"
},
{
"area_id": "110106",
"area_name": "丰台区",
"parent_id": "110100",
"short_name": "丰台",
"level": "3",
"city_code": "010",
"zip_code": "100071",
"merger_name": "北京,北京市,丰台区",
"pinyin": "Fengtai"
},
{
"area_id": "110107",
"area_name": "石景山区",
"parent_id": "110100",
"short_name": "石景山",
"level": "3",
"city_code": "010",
"zip_code": "100043",
"merger_name": "北京,北京市,石景山区",
"pinyin": "Shijingshan"
},
{
"area_id": "110108",
"area_name": "海淀区",
"parent_id": "110100",
"short_name": "海淀",
"level": "3",
"city_code": "010",
"zip_code": "100089",
"merger_name": "北京,北京市,海淀区",
"pinyin": "Haidian"
},
{
"area_id": "110109",
"area_name": "门头沟区",
"parent_id": "110100",
"short_name": "门头沟",
"level": "3",
"city_code": "010",
"zip_code": "102300",
"merger_name": "北京,北京市,门头沟区",
"pinyin": "Mentougou"
},
{
"area_id": "110111",
"area_name": "房山区",
"parent_id": "110100",
"short_name": "房山",
"level": "3",
"city_code": "010",
"zip_code": "102488",
"merger_name": "北京,北京市,房山区",
"pinyin": "Fangshan"
},
{
"area_id": "110112",
"area_name": "通州区",
"parent_id": "110100",
"short_name": "通州",
"level": "3",
"city_code": "010",
"zip_code": "101149",
"merger_name": "北京,北京市,通州区",
"pinyin": "Tongzhou"
},
{
"area_id": "110113",
"area_name": "顺义区",
"parent_id": "110100",
"short_name": "顺义",
"level": "3",
"city_code": "010",
"zip_code": "101300",
"merger_name": "北京,北京市,顺义区",
"pinyin": "Shunyi"
},
{
"area_id": "110114",
"area_name": "昌平区",
"parent_id": "110100",
"short_name": "昌平",
"level": "3",
"city_code": "010",
"zip_code": "102200",
"merger_name": "北京,北京市,昌平区",
"pinyin": "Changping"
},
{
"area_id": "110115",
"area_name": "大兴区",
"parent_id": "110100",
"short_name": "大兴",
"level": "3",
"city_code": "010",
"zip_code": "102600",
"merger_name": "北京,北京市,大兴区",
"pinyin": "Daxing"
},
{
"area_id": "110116",
"area_name": "怀柔区",
"parent_id": "110100",
"short_name": "怀柔",
"level": "3",
"city_code": "010",
"zip_code": "101400",
"merger_name": "北京,北京市,怀柔区",
"pinyin": "Huairou"
},
{
"area_id": "110117",
"area_name": "平谷区",
"parent_id": "110100",
"short_name": "平谷",
"level": "3",
"city_code": "010",
"zip_code": "101200",
"merger_name": "北京,北京市,平谷区",
"pinyin": "Pinggu"
},
{
"area_id": "110228",
"area_name": "密云县",
"parent_id": "110100",
"short_name": "密云",
"level": "3",
"city_code": "010",
"zip_code": "101500",
"merger_name": "北京,北京市,密云县",
"pinyin": "Miyun"
},
{
"area_id": "110229",
"area_name": "延庆县",
"parent_id": "110100",
"short_name": "延庆",
"level": "3",
"city_code": "010",
"zip_code": "102100",
"merger_name": "北京,北京市,延庆县",
"pinyin": "Yanqing"
}]
}
总结
查询中发现,有些完整的词搜索不到,拆解分别查询都可以查到,比如:使用“海州”去查询是查不到的,但是如果使用“海”或“州”都可以查询到“海州”。因为是分词把“海州”分成了“海”和“州”两个,所以使用“海州”搜索不到。
分词情况:http://192.168.43.100:9200/_analyze/?pretty
参数:{ "analyzer": "ik_max_word", "text": "海州" }
结果:{ "tokens": [ { "token": "海", "start_offset": 0, "end_offset": 1, "type": "CN_CHAR", "position": 0 }, { "token": "州", "start_offset": 1, "end_offset": 2, "type": "CN_CHAR", "position": 1 } ] }