安装ElasticSearch
- 安装1.8及以上的jdk
- https://www.elastic.co/cn/downloads/elasticsearch 下载对应版本
- 上传到云服务器 /usr/local/software/ 目录下
- tar -zxvf elasticsearch-7.12.1-linux-x86_64.tar.gz解压
- cd /usr/local/software/elasticsearch-7.12.1/bin
- 执行./elasticsearch报错
java.lang.RuntimeException: can not run elasticsearch as root
- 新建es用户
- cd /usr/local/software
- groupadd esgroup
- useradd esuser -g esgroup -p 123456
- chown -R esuser:esgroup elasticsearch-7.12.1/
- su - esuser
- ./elasticsearch 前台启动
- ./elasticsearch -d 后台启动 需要等一段时间
- 配置跨域访问 /usr/local/software/elasticsearch-7.12.1/config/elasticsearch.yml 最后添加下面两行
http.cors.enabled: true
http.cors.allow-origin: "*"
curl 127.0.0.1:9200 成功会有相应信息
如果出现 max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]错误 编辑 /etc/sysctl.conf,追加以下内容:vm.max_map_count=655360保存后,执行:sysctl -p
-
出现 max file descriptors [65535] for elasticsearch process is too low, increase to at least [65536] 切换到root用户编辑 /etc/security/limits.conf,追加以下内容
soft nofile 65536 hard nofile 65536
默认只允许本机访问 配合Nginx 实现外网访问
upstream es_pool{
server 127.0.0.1:9200;
}
upstream es_header_pool{
server 127.0.0.1:9100;
}
server {
listen 80;
server_name localhost;
location /es/ {
proxy_pass http://es_pool/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /es_header/ {
proxy_pass http://es_header_pool/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
- 允许内网访问的 elasticsearch.yml 配置文件
cluster.name: my-application
node.name: node-1
network.host: 0.0.0.0
http.port: 9200
discovery.seed_hosts: ["127.0.0.1", "[::1]"]
cluster.initial_master_nodes: ["node-1"]
http.cors.allow-origin: "*"
http.cors.enabled: true
http.cors.allow-headers : X-Requested-With,X-Auth-Token,Content-Type,Content-Length,Authorization
http.cors.allow-credentials: true
安装ElasticSearch-Head
通过https://nodejs.org/en/download/ 下载nodejs版本
上传到/usr/local/software下面
tar -xvf node-v14.17.0-linux-x64.tar.xz 解压
export PATH=$PATH:/usr/local/software/node-v14.17.0-linux-x64/bin
ln -s /usr/local/software/node-v14.17.0-linux-x64/bin/npm /usr/local/bin/
ln -s /usr/local/software/node-v14.17.0-linux-x64/bin/node /usr/local/bin/执行node -v 打印版本 成功
yum install -y unzip zip 安装unzip解压
上传到/usr/local/software/ unzip elasticsearch-head-master.zip
npm install -g grunt-cli 安装依赖
yum install bzip2 //可能会报解压错误 没有忽略即可
npm install cnpm -g --registry=https://registry.npm.taobao.org 使用npm因为网络原因总是报错
cd elasticsearch-head-master/ 执行 cnpm install
修改Gruntfile.js
connect: {
server: {
options: {
hostname: '*', # 添加这一行
port: 9100,
base: '.',
keepalive: true
}
}
}
- 修改_site下面的app.js 4388行左右将localhost替换成ElasticSearch的服务器地址
this.base_uri = this.config.base_uri || this.prefs.get("app-base_uri") || "http://192.168.0.199:9200";
- npm run start 启动
- nohup npm run start & 后台启动
安装 Kibana
- https://www.elastic.co/cn/downloads/kibana 下载 版本一定要和ElasticSearch一致
- 上传到服务器 /usr/local/software 并解压
- cd /usr/local/software
- mv kibana-7.12.1-linux-x86_64/ kibana
server.host: "192.168.0.199"
elasticsearch.hosts: ["http://192.168.0.199:9200"]
i18n.locale: "zh-CN"
- 执行bin目录下的kibana ./kibana --allow-root
- 访问 http://192.168.0.199:5601/
ElasticSearch 术语
- 索引index —— 拥有相似文档的集合
- 类型type —— 一个索引中可以定义多个类型
- 字段field —— 相当于数据库表中的字段
- 映射mapping —— 处理数据方式和规格方面做一些限制
- 文档document —— 一个文档是一个可被索引的基础单元
- 分片 —— 由于单台机器无法存储大量数据,ES 可以将一个索引中的数据切分为多个分片(Shard),分布在多台服务器上存储。
- 复制 —— 备份
操作
- 使用PUT请求添加text索引 http://192.168.0.199/es/test
- 新建索引的时候设置mapping信息 注意 7.4 默认不在支持指定索引类型 http://192.168.0.199/es/test1 下面是请求体
{
"mappings": {
"properties": {
"id": {
"type": "long",
"store": true
},
"title": {
"type": "text",
"store": true,
"analyzer": "standard"
},
"content": {
"type": "text",
"store": true,
"analyzer": "standard"
}
}
}
}
- 查看索引对应的映射 类型默认都是_doc
{
"mappings": {
"_doc": {
"properties": {
"content": {
"type": "text",
"store": true,
"analyzer": "standard"
},
"id": {
"type": "long",
"store": true
},
"title": {
"type": "text",
"store": true,
"analyzer": "standard"
}
}
}
}
}
- 索引创建完成后POST请求添加mapping信息 http://192.168.0.199/es/test/db1/_mapping?include_type_name=true 在test下面新增db1结果如下
{
"mappings": {
"db1": {
"properties": {
"content": {
"type": "text",
"store": true,
"analyzer": "standard"
},
"id": {
"type": "long",
"store": true
},
"title": {
"type": "text",
"store": true,
"analyzer": "standard"
}
}
}
}
}
- DELETE请求删除索引库 http://192.168.0.199/es/test1
- 添加文档(一条数据就是一个文档)http://192.168.0.199/es/test/db1/1 在db1类型下设置id为1的数据 下面是请求体 保持和映射一致就行 如果db1后面不加/1 会自动生成一个随机字符串id 操作时一般保持id字段和请求体里面的id字段保持一致
{
"id":1,
"title":"文档标题",
"content":"文档内容"
}
id设置相同数据会被覆盖 用来实现修改文档
DELETE方法删除文档 http://192.168.0.199/es/test/db1/1
-
查询
根据id查询 GET请求 http://192.168.0.199/es/test/db1/1 即可
-
关键字 POST http://192.168.0.199/es/test/db1/_search 只能使用一个汉字
{ "query":{ "term":{ "title":"文" //在title字段上查询关键字有文的 } } }
queryString查询 路径同上
{ "query_string":{ "term":{ "default_field":"title", "query":"文档" } } }
- 先分词 如果title中包含文 或者 档 的都会被查出来
- 查看分词情况 GET 请求 http://192.168.0.199/es/test/_analyze
{ "analyzer" : "standard", "text": ["文档标题2"] }
- 关键词查询 like query_string 先对查询内容分词
{ "query":{ "query_string":{ "query":"title:(\"题2\")", "default_operator": "and" } } }
or
{ "query": { "match_phrase": { "title": "题2" } } }
安装中文分词器IK
ElasticSearch内置分词器
- standard分词器:(默认分词器)它会将词汇单元转换成小写形式,并除去停用词(a、an、the等)和标点符号,支持中文采用的方法为单字切分。
- simple分词器:首先会通过非字母字符来分割文本信息,然后将词汇单元统一成小写形式,该分词器会去掉数据类型的字符。
- Whitespace分词器:仅仅是去掉空格,对字符没有lowcase化,不支持中文;并且不对生成的词汇单元进行其他的标准化处理。
- language分词器:特定语言的分词器,不支持中文
中文分词器的安装
- https://github.com/medcl/elasticsearch-analysis-ik/releases 下载最新版本的zip包
- cd /usr/local/software/elasticsearch-7.12.1/plugins/
- mkdir ik
- 把文件移动到ik目录下
- cd ik/
- unzip elasticsearch-analysis-ik-7.12.1.zip
- 切换用户重启 elasticsearch
- 新建映射的时候就需使用ik分析器
- ik_smart(最小) 和 ik_max_word(最细)的区别 举例分析程序员 ik_smart 会解析成程序员 ik_max_word 会解析成三个分别是 程序员 程序 员
{
"mappings": {
"db1": {
"properties": {
"content": {
"type": "text",
"store": true,
"analyzer": "ik_smart"
},
"id": {
"type": "long",
"store": true
},
"title": {
"type": "text",
"store": true,
"analyzer": "ik_max_word"
}
}
}
}
}
集群
修改config\elasticsearch.yml文件添加
#集群名称,保证唯一
cluster.name: my‐elasticsearch
#节点名称,必须不一样
node.name: node‐1 # node‐2 node‐3
#必须为本机的ip地址
network.host: 192.168.0.199 # 0.200 0.201
#服务端口号
http.port: 9200
#服务TCP端口号
transport.tcp.port: 9300
#设置集群自动发现机器ip集合
discovery.zen.ping.unicast.hosts:["192.168.0.199:9300","192.168.0.200:9300","192.168.0.201:9302"]
SpringBoot 整合
- 创建工程 并引入依赖 内部引用的es版本必须要和服务器安装的匹配
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
<version>2.3.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
- application.yml配置
spring:
elasticsearch:
rest:
uris: 192.168.0.199:9200
username: my-application
# uris:192.168.0.199:9200,192.168.0.200:9200,192.168.0.201:9200,
- 实体与document对应类
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
@Document(indexName = "stu") //索引名称
@Data
public class Stu {
@Id
private Long stuId; //会创建相同的文档id 否则自动生成
@Field(store = true)
private String name;
@Field(store = true)
private Integer age;
}
- 实体类中新加四个字段 会自动添加到索引里面
@Field(store = true)
private Float money;
@Field(store = true, type = FieldType.Keyword)
private String sign;
@Field(store = true)
private String description;
@Field(type = FieldType.Date, format = DateFormat.date_time)
private Date recordTime;
- 关于常用方法 2.3.10 版本中的
@RunWith(SpringRunner.class)
@SpringBootTest
public class ESTest {
/**
* 一般不建议用Spring来创建/更新 删除索引
* 一般针对文档进行CRUD操作
*/
@Autowired
private ElasticsearchRestTemplate elasticsearchRestTemplate;
/**
* 创建/更新索引 如果存在 就更新 不会再创建 一般不使用
*/
@Test
public void createIndexStu() {
Stu stu = new Stu();
stu.setStuId(1006L);
stu.setAge(33);
stu.setName("李七");
stu.setRecordTime(new Date());
IndexQuery indexQuery = new IndexQueryBuilder().withObject(stu).build();
IndexCoordinates indexCoordinates = elasticsearchRestTemplate.getIndexCoordinatesFor(Stu.class);
elasticsearchRestTemplate.index(indexQuery, indexCoordinates);
}
/**
* 更新文档
*/
@Test
public void updateStuDoc() {
Document document = Document.create();
document.put("name", "李四");
document.put("age", 20);
UpdateQuery updateQuery = UpdateQuery.builder("1000").withDocument(document).build();
elasticsearchRestTemplate.update(updateQuery, elasticsearchRestTemplate.getIndexCoordinatesFor(Stu.class));
}
/**
* 查询 + 高亮显示
*/
@Test
public void queryStuDoc() {
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
//必须满足的条件 加keyword不会拆分 不加会拆分成李和四
// boolQueryBuilder.must().add(new TermQueryBuilder("name.keyword", "李四"));
// boolQueryBuilder.must().add(new TermQueryBuilder("name", "四"));
// 查询3天内数的数据
RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("recordTime");
rangeQueryBuilder.gte(LocalDateTime.now().minusDays(3));
// 或者下面的
// rangeQueryBuilder
// .from("2021-05-16T00:00:00.000Z")
// .to("2021-05-19T23:59:59.000Z");
// boolQueryBuilder.must().add(rangeQueryBuilder);
// 分页查询20条
PageRequest pageRequest = PageRequest.of(0, 20, Sort.by("stuId").descending());
NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder();
searchQueryBuilder
.withQuery(boolQueryBuilder)
// 亲测使用.keyword有值但是高亮数据size = 0
.withHighlightBuilder(new HighlightBuilder().field("name")
.preTags("<font color='red'>")
.postTags("</font>"))
.withPageable(pageRequest);
Query searchQuery = searchQueryBuilder.build();
SearchHits<Stu> result = elasticsearchRestTemplate.search(searchQuery, Stu.class);
List<SearchHit<Stu>> hitList = result.getSearchHits();
System.out.println("hit size -> {}" + hitList.size());
hitList.forEach(hit -> {
Map<String, List<String>> highlightFields = hit.getHighlightFields();
List<String> nameHighlight = highlightFields.get("name");
if (nameHighlight != null) {
for (String text : nameHighlight) {
hit.getContent().setName(text);
}
}
System.out.println("返回数据:" + hit.getContent().toString());
});
}
/**
* 删除文档
*/
@Test
public void delIndexDoc() {
elasticsearchRestTemplate.delete("1000", elasticsearchRestTemplate.getIndexCoordinatesFor(Stu.class));
}
}