ElasticSearch


这篇ElasticSearch文章是基于 狂神说Java3y 两位大佬所写的ElasticSearch文章的笔记与总结,仅供个人学习和复习用。欲学习ElasticSearch知识推荐前往两位大佬的博客中学习。

Windows下ElasticSearch安装

下载地址

https://www.elastic.co/cn/elasticsearch/

下载解压即可使用。

安装

直接解压就行,注意因为8.0版本后开启了ssl认证以及需要密码等问题可以参考以下链接进行处理。Windows10下安装Elasticsearch8.1.1过程遇到的问题

上面那篇是比较安全的做法,如果不想那么麻烦,或者不考虑安全可以参考以下的做法。ElasticSearch 爬坑记录

在config目录的elasticsearch.yml中修改配置

提示:个人经历,可能得先运行启动elasticsearch.bat,闪退之后重新打开yml文件会多出需要改的那几行配置。

1.关闭ssl认证

# Enable encryption for HTTP API client connections, such as Kibana, Logstash, and Agents
xpack.security.http.ssl:
  enabled: false
  keystore.path: certs/http.p12

2.关闭密码验证

# Enable security features
xpack.security.enabled: false

运行bin目录的elasticsearch.bat,在浏览器打开127.0.0.1:9200出现以下界面则成功。

可视化界面安装(可忽略)

下载地址

https://github.com/mobz/elasticsearch-head

解压后cmd打开安装依赖

cd elasticsearch-head
npm install
npm run start
open http://localhost:9100/

如存在跨越问题需修改ElasticSearch的配置

http.cors.enabled: true
http.cors.allow-origin: "*"

ik分词器

下载地址:https://github.com/medcl/elasticsearch-analysis-ik

下载后在elasticsearch的plugins目录新建ik文件夹并解压到这里。(注意在安装路径中不要存在空格否则将导致ElasticSearch和Kibana启动失败)

Rest风格

测试用例

1.创建一个索引

PUT /索引名/类型名(过时)/文档id
{请求体}

PUT /test1/_doc/1
{
  "name": "zsky",
  "age": 2
}

PUT /test2
{
  "mappings": {
    "properties": {
      "name":{
        "type":"text"
      },
      "age":{
        "type": "long"
      },
      "birthday":{
        "type":"date"
      }
    }
  }
}

2.修改索引

PUT /test2/_doc/1
{
  "name": "zsky2",
  "age": 15,
  "birthday": "1998-10-14"
}

POST /test2/_update/1
{
  "doc":{
    "name":"1111"
  }
}

3.删除文档

DELETE /test2/_doc/2

4.查询文档

GET /zsky/_search?q=name:王五3

结果:
{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.2814486,
    "hits" : [
      {
        "_index" : "zsky",
        "_id" : "3",
        "_score" : 1.2814486,
        "_source" : {
          "name" : "王五2",
          "age" : 1,
          "desc" : "333333",
          "tags" : [
            "渣男",
            "交友"
          ]
        }
      }
    ]
  }
}


注意以上结果当路径的name:不带双引号时是分词查询即将王五3分成王五和3去like模糊查询能查询到结果,带双引号时则不分词用双引号内容like模糊查询所以查不到结果。如果需要精准查询则改为

GET /zsky/_search
{
  "query": {
    "match": {
      "name.keyword": "王"
    }
  }
}


GET /zsky/_search
{
  "query": {
    "match": {
      "name": "王"
    }
  },
  "_source": ["name","desc","age"],  //只查询的字段
  "sort": [                          //排序
    {
      "age": {
        "order": "asc"
      }
    }
  ],
  "from": 0,     //分页起始坐标
  "size": 2      //每次查询的数据
}

5.高亮

GET /zsky/_search
{
  "query": {
    "match": {
      "name": "王 李"
    }
  },
  "highlight": {
    "fields": {
      "name": {}
    }
  }
}

结果:
{
  "took" : 242,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 3,
      "relation" : "eq"
    },
    "max_score" : 1.4877305,
    "hits" : [
      {
        "_index" : "zsky",
        "_id" : "2",
        "_score" : 1.4877305,
        "_source" : {
          "name" : "李四",
          "age" : 11,
          "desc" : "222222",
          "tags" : [
            "美女",
            "唱歌"
          ]
        },
        "highlight" : {
          "name" : [
            "<em></em>四"
          ]
        }
      },
      {
        "_index" : "zsky",
        "_id" : "4",
        "_score" : 0.57843524,
        "_source" : {
          "name" : "王三",
          "age" : 7,
          "desc" : "444444444444",
          "tags" : [
            "学生",
            "看书"
          ]
        },
        "highlight" : {
          "name" : [
            "<em></em>三"
          ]
        }
      },
      {
        "_index" : "zsky",
        "_id" : "3",
        "_score" : 0.4889865,
        "_source" : {
          "name" : "王五2",
          "age" : 1,
          "desc" : "333333",
          "tags" : [
            "渣男",
            "交友"
          ]
        },
        "highlight" : {
          "name" : [
            "<em></em>五2"
          ]
        }
      }
    ]
  }
}

集成SpringBoot

导入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.7.0</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.zsky</groupId>
	<artifactId>es-api</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>es-api</name>
	<description>Demo project for Spring Boot</description>
	<properties>
		<java.version>1.8</java.version>
		<!--自己定义es版本依赖,保证与本地一致-->
	</properties>
	<dependencies>
		<dependency>
			<groupId>co.elastic.clients</groupId>
			<artifactId>elasticsearch-java</artifactId>
			<version>8.2.0</version>
		</dependency>

		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
			<version>2.12.3</version>
		</dependency>
		<dependency>
			<groupId>jakarta.json</groupId>
			<artifactId>jakarta.json-api</artifactId>
			<version>2.0.1</version>
		</dependency>


		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-configuration-processor</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>javax.annotation</groupId>
			<artifactId>javax.annotation-api</artifactId>
			<version>1.3.2</version>
		</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>
		</dependency>

		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>1.2.75</version>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<excludes>
						<exclude>
							<groupId>org.projectlombok</groupId>
							<artifactId>lombok</artifactId>
						</exclude>
					</excludes>
				</configuration>
			</plugin>
		</plugins>
	</build>

</project>

修改配置文件

elasticsearch:
  hosts: "127.0.0.1:9200"

配置类

ElasticSearchClientConfig

package com.zsky.esapi.config;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.ElasticsearchTransport;
import co.elastic.clients.transport.rest_client.RestClientTransport;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;

@ConfigurationProperties(prefix = "elasticsearch")//配置配置信息的前缀
@Configuration
public class ElasticSearchClientConfig {
    
    private String hosts;
    
    @Bean
    public RestClient restClient(){
        // Create the low-level client
        HttpHost[] httpHosts = toHttpHost();

        RestClient restClient = RestClient.builder(httpHosts).build();
        return restClient;
    }
    
    @Bean
    public ElasticsearchClient esClient(){
        RestClient restClient = restClient();
        ElasticsearchTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
        //es 客户端
        ElasticsearchClient client = new ElasticsearchClient(transport);
        return client;
    }
    
    /*
    解析hosts
     */
    private HttpHost[] toHttpHost(){
        if(!StringUtils.hasLength(hosts)){
            throw new RuntimeException("elasticsearch.host不能为空!");
        }
        String[] hostArray = hosts.split(",");;
        HttpHost[] httpHosts =  new HttpHost[hostArray.length];
        HttpHost httpHost;
        for (int i = 0; i < hostArray.length; i++) {
            String[] strings = hostArray[i].split(":");
            httpHost = new HttpHost(strings[0], Integer.parseInt(strings[1]), "http");
            httpHosts[i] = httpHost;
        }

        return httpHosts;
    }

    public String getHosts() {
        return hosts;
    }

    public void setHosts(String hosts) {
        this.hosts = hosts;
    }
}

实体类

User

package com.zsky.esapi.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Component;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Component
public class User {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

测试类

package com.zsky.esapi;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.AcknowledgedResponse;
import co.elastic.clients.elasticsearch._types.Time;
import co.elastic.clients.elasticsearch._types.query_dsl.QueryBuilders;
import co.elastic.clients.elasticsearch._types.query_dsl.TermQuery;
import co.elastic.clients.elasticsearch.core.*;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.indices.*;
import co.elastic.clients.elasticsearch.indices.ExistsRequest;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.ElasticsearchTransport;
import co.elastic.clients.transport.endpoints.BooleanResponse;
import co.elastic.clients.transport.rest_client.RestClientTransport;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.zsky.esapi.pojo.User;
import org.elasticsearch.client.RestClient;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@SpringBootTest
class EsApiApplicationTests {


	@Autowired
	private RestClient restClient;
	
	@Autowired
	@Qualifier("esClient")
	private ElasticsearchClient esClient;

	@Test
	void createIndex() throws IOException {
		ElasticsearchTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
		//es 客户端
		ElasticsearchClient client = new ElasticsearchClient(transport);

		CreateIndexResponse indexResponse = client.indices().create(c -> c.index("zskytest"));
		System.out.println(indexResponse.index());
	}

	@Test
	void createIndex2() throws IOException {
		CreateIndexResponse indexResponse = esClient.indices().create(c -> c.index("zskytest22"));
		System.out.println(indexResponse.index());
	}
	
	@Test
	void existIndex() throws IOException {
		ExistsRequest existsRequest = new ExistsRequest.Builder().index("zskytest").build();
		BooleanResponse exists = esClient.indices().exists(existsRequest);
		System.out.println(exists.value());
	} 

	
	@Test
	void deleteIndex() throws IOException {
		DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest.Builder().index("zskytest22").build();
		AcknowledgedResponse delete = esClient.indices().delete(deleteIndexRequest);
		System.out.println(delete.acknowledged());
	}
	
	//文档操作
	@Test
	void addDocument() throws IOException {
		//创建对象
		User user = new User("zsky", 15);
		//创建请求  规则 put /zskytest/_doc/1
		IndexRequest<User> request = IndexRequest.of(i -> i.index("zskytest").id("1").document(user));
		// 发送请求,获取响应结果
		IndexResponse response = esClient.index(request);

		System.out.println(response.toString());
		System.out.println(response.result());
		
		//非对象方式创建文档
		Map<String,String> map = new HashMap<>();
		map.put("name","张三");
		map.put("age","22");
		CreateRequest createRequest = CreateRequest.of(i -> i.index("zskytest").id("2").document(map));
		CreateResponse createResponse = esClient.create(createRequest);
		System.out.println(createResponse.result());
	}
	
	//判断文档是否存在
	@Test
	void testIsExists() throws IOException {
		GetResponse<User> response = esClient.get(g -> g.index("zskytest").id("1"),User.class);
		if(response.found()){
			User user = response.source();
			System.out.println("查询到文档信息");
			
		}else {
			System.out.println("未查询到文档信息");
		}
		
		//根据需要同过json获取,可不用实体类  注意ObjectNode需要Maven配置json 例如本例中引入的包com.fasterxml.jackson.databind.node.ObjectNode;
		GetResponse<ObjectNode> response2 = esClient.get(g -> g.index("zskytest").id("1"),ObjectNode.class);
		if(response.found()){
			ObjectNode json = response2.source();
			String name = json.get("name").asText();
			System.out.println("查询到文档信息");
			System.out.println(response2.toString());
		}else {
			System.out.println("未查询到文档信息");
		}
	}
	
	//查询所有文档
	@Test
	void searchAllIndex() throws IOException {
		List<Object> resultList = new ArrayList<>();
		SearchRequest searchRequest = SearchRequest.of(i -> i.index("zskytest"));
		SearchResponse<Object> response = esClient.search(searchRequest,Object.class);
		if(response.hits() != null){
			List<Hit<Object>> list = response.hits().hits();
			for(Hit<Object> hit : list){
				Object t = (Object) hit.source();
				resultList.add(t);
			}
		}
		System.out.println(response.hits());
	}

	//修改文档
	@Test
	void updateDoc() throws IOException {
		User user = new User("zsky", 10);
		UpdateRequest updateRequest =  UpdateRequest.of(i -> i.index("zskytest").id("1").doc(user));
		UpdateResponse updateResponse = esClient.update(updateRequest,User.class);
		System.out.println(updateResponse.result());

		//不使用实体类方式修改文档
		Map<String,String> map = new HashMap<>();
		map.put("name","张三");
		map.put("age","25");
		UpdateRequest updateRequest2 = UpdateRequest.of(i -> i.index("zskytest").id("2").doc(map));
		UpdateResponse updateResponse2 = esClient.update(updateRequest2,Object.class);
		System.out.println(updateResponse2.result());
	}
	
	//删除文档
	@Test
	void deleteDoc() throws IOException {
		DeleteRequest request = DeleteRequest.of(i -> i.index("zskytest").id("2"));
		DeleteResponse response = esClient.delete(request);
		System.out.println(response.result());
	}
	
	@Test
	void queryDoc() throws IOException {
		List<Object> resultList = new ArrayList<>();
		TermQuery query = QueryBuilders.term().field("name").value("张三").build();
		SearchRequest request = new SearchRequest.Builder().index("zskytest").query(query._toQuery()).build();
		SearchResponse<Object> response = esClient.search(request,Object.class);
		if(response.hits() != null){
			List<Hit<Object>> list = response.hits().hits();
			for(Hit<Object> hit : list){
				Object t = (Object) hit.source();
				resultList.add(t);
			}
		} 
	}
}

文章作者: Sky
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Sky !
评论
  目录