学习es可以看:狂神说es
Elasticsearch是一个基于Lucene(java)的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口,区别于solr的webservice。
jdk1.8 ElasticSearch客户端 界面工具(Kibana)
官网地址 https://www.elastic.co/cn/downloads/
windows下 解压即可使用
启动 elasticsearch-7.7.0\bin\elasticsearch.bat 访问地址 localhost:9200
跨域配置 elasticsearch-7.7.0\config\elasticsearch.yml 增加如下代码
http.cors.enabled: true
http.cors.allow-origin: "*"
官网地址 https://github.com/mobz/elasticsearch-head
#启动需要nodejs环境 启动命令 访问地址 localhost:9100
cd D:\sde\elasticsearch\elasticsearch-head-master
npm install
npm run start
当然,你可以直接下载chorm浏览器的插件
官网地址 https://www.elastic.co/cn/downloads/
windows下 解压即可使用
启动 kibana-7.7.1-windows-x86_64\bin 访问地址 localhost:5601
#汉化 kibana-7.7.1-windows-x86_64\config\kibana.yml 增加如下代码
i18n.locale: “zh-CN”
回到顶部
官网地址 https://github.com/medcl/elasticsearch-analysis-ik/releases
解压到 D:\sde\elasticsearch\elasticsearch-7.7.0\plugins\analysis-ik 目录没有新建analysis-ik 目录名称不重要,随意起
检查是否加载分词器
cd D:\sde\elasticsearch\elasticsearch-7.7.0\bin
elasticsearch-plugin list
算法 ik_smart(最少切分) ik_max_word(最细粒度切分) 及用kibana校验 默认keywork standard
GET _analyze
{
"analyzer": "ik_max_word",
"text": ["美国民主党"]
}
GET _analyze
{
"analyzer": "ik_smart",
"text": ["美国民主党"]
}
扩充字典(人名、网络流行语)
method | url | desc |
---|---|---|
PUT | localhost:9200/索引名称/类型名称/文档id | 创建文档(指定文档id) |
POST | localhost:9200/索引名称/类型名称 | 创建文档(随机id) |
POST | localhost:9200/索引名称/_update/文档id | 修改文档 |
DELETE | localhost:9200/索引名称/类型名称/文档id | 删除文档 by id |
GET | localhost:9200/索引名称/类型名称/文档id | 查询文档 by id |
POST | localhost:9200/索引名称/_search | 查询所有文档 |
#创建空库
PUT /test2
{
}
#创建索引 及 规定字段类型
PUT /test3
{
"mappings": {
"properties": {
"name":{
"type": "text"
},
"age":{
"type": "integer"
},
"birth":{
"type": "date"
}
}
}
}
#创建数据
PUT /wanghl/_doc/2
{
"name":"花木兰",
"age":67,
"tags":["战士","上单","女"]
}
4.2 删除
#删除索引
DELETE test2
#删除文档
DELETE test1/_doc/3
4.3修改
#修改文档
POST /test1/_update/4
{
"doc":{
"name":"红桃A"
}
}
#获取索引库
GET test3
#获取文档by文档id
GET wanghl/_doc/2
#根据属性查询 简写
GET wanghl/_search?q=name:李
#构建式查询
#_source 字段过滤 不写默认 select *
# from size 分页
GET /wanghl/_search
{
"query": {
"match": {
"tags": "男"
}
},
"_source": ["name","tags"],
"from":0,
"size":1
}
#多条件查询 must 相当于 and should 相当于 or
GET wanghl/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"tags": "男 下路"
}
}
],
"must_not": [
{
"match": {
"age": "3"
}
}
]
}
}
}
# 查询过滤 + 高亮显示
GET wanghl/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"tags": "男"
}
}
] ,
"filter": [
{
"range": {
"age": {
"gte": 10,
"lte": 200
}
}
}
]
}
},
"highlight": {
"pre_tags": "",
"post_tags": "",
"fields": {
"tags": {}
}
}
}
pom文件添加依赖
org.springframework.boot
spring-boot-starter-data-elasticsearch
所有依赖
com.changgou
changgou_common
1.0-SNAPSHOT
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
org.springframework.boot
spring-boot-starter-data-elasticsearch
com.changgou
changgou_service_goods_api
1.0-SNAPSHOT
com.changgou
changgou_service_search_api
1.0-SNAPSHOT
org.springframework.boot
spring-boot-starter-amqp
spring:
data:
elasticsearch:
cluster-name: elasticsearch
cluster-nodes: 192.168.200.128:9300
server:
port: 9009
spring:
application:
name: search
rabbitmq:
host: 192.168.200.128
redis:
host: 192.168.200.128
main:
allow-bean-definition-overriding: true #当遇到同样名字的时候,是否允许覆盖注册
data:
elasticsearch:
cluster-name: elasticsearch
cluster-nodes: 192.168.200.128:9300
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:6868/eureka
instance:
prefer-ip-address: true
feign:
hystrix:
enabled: true
client:
config:
default: #配置全局的feign的调用超时时间 如果 有指定的服务配置 默认的配置不会生效
connectTimeout: 600000 # 指定的是 消费者 连接服务提供者的连接超时时间 是否能连接 单位是毫秒
readTimeout: 600000 # 指定的是调用服务提供者的 服务 的超时时间() 单位是毫秒
#hystrix 配置
hystrix:
command:
default:
execution:
timeout:
#如果enabled设置为false,则请求超时交给ribbon控制
enabled: false
isolation:
strategy: SEMAPHORE
狂神说中需注册es client对象
package com.nesc.esapi.config;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 定义高版本ES实例对象
* @author wanghl
* @date 2020/7/17 9:23
**/
@Configuration
public class ElasticSearchClientConfig {
@Bean
public RestHighLevelClient restHighLevelClient() {
RestHighLevelClient client = new RestHighLevelClient(
RestClient.builder(
new HttpHost("127.0.0.1", 9200, "http")
)
);
return client;
}
}
package com.nesc.esapi;
import com.alibaba.fastjson.JSONObject;
import com.nesc.esapi.domain.User;
import lombok.SneakyThrows;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.io.IOException;
import java.util.ArrayList;
/**
* ES client api测试
*/
@SpringBootTest
class EsApiApplicationTests {
@Autowired
RestHighLevelClient restHighLevelClient;
/**
* 新建索引
* @throws Exception
*/
@Test
void testCreateIndex() throws IOException {
//创建请求
CreateIndexRequest request = new CreateIndexRequest("testapi");
CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(request,RequestOptions.DEFAULT);
}
/**
* 查询索引
* @throws IOException
*/
@Test
void testExistIndex() throws IOException {
GetIndexRequest request = new GetIndexRequest("testapi");
boolean exists = restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);
System.out.println(exists);
}
/**
* 删除索引
* @throws IOException
*/
@Test
void testDeleteIndex() throws IOException {
DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest("testapi");
AcknowledgedResponse delete = restHighLevelClient.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);
System.out.println(delete);
}
/**
* 创建文档
* @throws IOException
*/
@Test
void testCreateDocument() throws IOException {
IndexRequest indexRequest = new IndexRequest("testapi");
User user = new User("张飞","射手");
IndexRequest source = indexRequest.source(JSONObject.toJSONString(user), XContentType.JSON);
IndexResponse index = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
System.out.println(index.toString());
}
/**
* 文档是否存在
* @throws IOException
*/
@Test
void testExistDocument() throws IOException {
//testapi 索引中 是否存在 1 的文档
GetRequest getRequest = new GetRequest("testapi", "1");
boolean exists = restHighLevelClient.exists(getRequest, RequestOptions.DEFAULT);
System.out.println(exists);
}
/**
* 获取文档信息
* @throws IOException
*/
@Test
void testGetDocument() throws IOException {
GetRequest getRequest = new GetRequest("testapi", "gBd0W3MBYL0QvcF5Z9tv");
GetResponse documentFields = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT);
System.out.println(documentFields.getSource());
}
/**
* 获取文档信息
* @throws IOException
*/
@Test
void testUpdatDocument() throws IOException {
UpdateRequest updateRequest = new UpdateRequest("testapi", "jxeBW3MBYL0QvcF5idvD");
User user = new User("张飞","坦克");
updateRequest.doc(JSONObject.toJSONString(user),XContentType.JSON);
UpdateResponse update = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
System.out.println(update.status());
}
/**
* 删除文档信息
* @throws IOException
*/
@Test
void testDeleteDocument() throws IOException {
DeleteRequest deleteRequest = new DeleteRequest("testapi", "jxeBW3MBYL0QvcF5idvD");
DeleteResponse delete = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
System.out.println(delete.status());
}
/**
* 查询文档
*/
@Test
void testSearchDocument() throws IOException {
SearchRequest searchRequest = new SearchRequest("testapi");
//匹配字段
MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("username", "李白");
//构建查询器
searchRequest.source(new SearchSourceBuilder().query(matchQueryBuilder));
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
System.out.println(searchResponse.getHits().getTotalHits());
}
// 批量插入
@Test
void bulkDocument() throws IOException {
ArrayList users = new ArrayList<>();
users.add(new User("aa", 10));
users.add(new User("bb", 11));
users.add(new User("cc", 12));
BulkRequest bulkRequest = new BulkRequest();
bulkRequest.timeout("10s");
for (int i = 0; i < users.size(); i++) {
bulkRequest.add(new IndexRequest("wuf_index").id("" + (i + 1)).source(JSON.toJSONString(users.get(i)),XContentType.JSON));
}
BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
System.out.println(bulk);
System.out.println(bulk.status());
System.out.println(bulk.hasFailures()); // 返回false代表成功
}
//org.elasticsearch.action.bulk.BulkResponse@1f39269d
//OK
//false
// 查询
@Test
void search() throws IOException {
// 查询请求
SearchRequest searchRequest = new SearchRequest("wuf_index");
// 查询构造
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
// 查询条件 1和2
// TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name","aa");
QueryBuilder termQueryBuilder = new TermQueryBuilder("name", "aa");
// searchSourceBuilder.highlighter();
searchSourceBuilder.query(termQueryBuilder);
searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
searchRequest.source(searchSourceBuilder);
SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
System.out.println(search);
System.out.println(JSON.toJSONString(search.getHits()));
System.out.println("----------------------------------");
for (SearchHit hit : search.getHits()) {
System.out.println(hit.getSourceAsMap());
}
System.out.println("===========================================");
for (SearchHit hit : search.getHits().getHits()) {
System.out.println(hit.getSourceAsMap());
}
}
//{"took":12,"timed_out":false,"_shards":{"total":1,"successful":1,"skipped":0,"failed":0},"hits":{"total":{"value":1,"relation":"eq"},"max_score":0.9808291,"hits":[{"_index":"zgc_index","_type":"_doc","_id":"1","_score":0.9808291,"_source":{"age":10,"name":"aa"}}]}}
//{"fragment":true,"hits":[{"fields":{},"fragment":false,"highlightFields":{"$ref":"$.hits[0].fields"},"id":"1","matchedQueries":[],"primaryTerm":0,"rawSortValues":[],"score":0.9808291,"seqNo":-2,"sortValues":[],"sourceAsMap":{"name":"aa","age":10},"sourceAsString":"{\"age\":10,\"name\":\"aa\"}","sourceRef":{"fragment":true},"type":"_doc","version":-1}],"maxScore":0.9808291,"totalHits":{"relation":"EQUAL_TO","value":1}}
//----------------------------------
//{name=aa, age=10}
//===========================================
//{name=aa, age=10}
}
创建和ES索引库映射实体类SkuInfo.java
@Document(indexName = "skuinfo", type = "docs")
public class SkuInfo implements Serializable {
//商品id,同时也是商品编号
@Id
@Field(index = true, store = true, type = FieldType.Keyword)
private Long id;
//SKU名称
@Field(index = true, store = true, type = FieldType.Text, analyzer = "ik_smart")
private String name;
//商品价格,单位为:元
@Field(index = true, store = true, type = FieldType.Double)
private Long price;
//库存数量
@Field(index = true, store = true, type = FieldType.Integer)
private Integer num;
//商品图片
@Field(index = false, store = true, type = FieldType.Text)
private String image;
//商品状态,1-正常,2-下架,3-删除
@Field(index = true, store = true, type = FieldType.Keyword)
private String status;
//创建时间
private Date createTime;
//更新时间
private Date updateTime;
//是否默认
@Field(index = true, store = true, type = FieldType.Keyword)
private String isDefault;
//SPUID
@Field(index = true, store = true, type = FieldType.Long)
private Long spuId;
//类目ID
@Field(index = true, store = true, type = FieldType.Long)
private Long categoryId;
//类目名称
@Field(index = true, store = true,type = FieldType.Keyword)
private String categoryName;
//品牌名称
@Field(index = true, store = true,type = FieldType.Keyword)
private String brandName;
//规格
private String spec;
//规格参数
private Map specMap;
......get和set方法......
创建ES操作的Dao接口
public interface SearchMapper extends ElasticsearchRepository {
}
将商品信息导入(主要根据SearchMapper操作数据,ElasticsearchTemplate操作索引)
@Service
public class EsManagerServiceImpl implements EsManagerService {
@Autowired
private SearchMapper searchMapper;
@Autowired
private SkuFeign skuFeign;
@Autowired
private ElasticsearchTemplate esTemplate;
/**
* 创建索引库结构
*/
@Override
public void createIndexAndMapping() {
//创建索引
esTemplate.createIndex(SkuInfo.class);
//创建映射
esTemplate.putMapping(SkuInfo.class);
}
/**
* 根据spuid导入数据到ES索引库
* @param spuId 商品id
*/
@Override
public void importDataToESBySpuId(String spuId) {
List skuList = skuFeign.findSkuListBySpuId(spuId);
List skuInfos = JSON.parseArray(JSON.toJSONString(skuList), SkuInfo.class);
for (SkuInfo skuInfo : skuInfos) {
skuInfo.setSpecMap(JSON.parseObject(skuInfo.getSpec(), Map.class));
}
searchMapper.saveAll(skuInfos);
}
/**
* 导入全部数据到ES索引库
*/
@Override
public void importAll() {
Map paramMap = new HashMap();
paramMap.put("status", "1");
Result result = skuFeign.findList(paramMap);
List skuInfos = JSON.parseArray(JSON.toJSONString(result.getData()), SkuInfo.class);
for (SkuInfo skuInfo : skuInfos) {
skuInfo.setPrice(skuInfo.getPrice());
skuInfo.setSpecMap(JSON.parseObject(skuInfo.getSpec(), Map.class));
}
searchMapper.saveAll(skuInfos);
}
}