承接上文: Elasticearch 搜索引擎
Boot 整合 Elasticearch
- 普普通通来个Boot 工程:
集成Elasticearch
- 依赖,配置,各种api对象操作使用!
Elasticearch依赖配置:
pom.xml
<dependencies>
<!-- Elasticsearch高级客户端。内部提供api 方法可以直接完成一些 http请求的调用,只需要输入对应参数即可,内部自动完成 -->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>6.5.4</version>
</dependency>
<!-- Elasticsearch 的依赖jar -->
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>6.5.4</version> <!-- 版本! -->
</dependency>
</dependencies>
配置文件 .yml
application.yml
#yml 配置定义自己的Elasticearch 启动服务运行端口;
my:
es:
host: 127.0.0.1:9200 #集群环境可以使用 ,xxx.x.x.x:9200,xxx.x.x.x:9200 来表示;
Elasticearch的配置类:
- 对Elasticearch 集群ip端口的控制:
EsConfig
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class EsConfig {
@Value("${my.es.host}") //@Value() 获取.yml 中配置后面方便,集群操作!
private String hostList;
@Bean //创建RESTful 的请求客户端对象, @Bean注入到SPring容器中!
public RestHighLevelClient client() {
//拆分hostList 逗号, 获得集群的ip集群数组!
String[] hostStr = hostList.split(",");
//创建HttpHost数组,其中存放es主机和端口的配置信息
HttpHost[] httpHosts = new HttpHost[hostStr.length];
//循环遍历: 0获取第一参数ip 1第二个参数 端口!
for (int i = 0; i < hostStr.length; i ) {
String str = hostStr[i];
httpHosts[i] = new HttpHost(str.split(":")[0], Integer.parseInt(str.split(":")[1]), "http");
}
//存放在RestHighLevelClient,管理集群的ip 端口;
return new RestHighLevelClient(RestClient.builder(httpHosts));
}
}
主程序类:
TestRun.Java
import com.wsm.service.EsService;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication //Boot的启动注解
public class TestRun {
public static void main(String[] args) throws Exception {
//Boot,启动入口
ConfigurableApplicationContext run = SpringApplication.run(TestRun.class, args);
//通过run 起运行对象,获取到Spring容器中的对象!必须使用run来获取,不然直接new 会null pointer!
//EsService 来源于Service层的实际代码操作!
EsService es = run.getBean(EsService.class);
es.deleteIndex(); //删除索引库!
}
}
正片开始:EsService
上面只是基本的环境搭建的简单配置, 下面才是Elasticearch 的关键代码部分:
基本,增删改 案例:
删除索引库
- Delete 请求:
http://localhost:9200/索引
直接删除索引
EsService.Java
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
@Service
public class EsService {
@Autowired
//RestHighLevelClien REST高级客户端对象,并自动映射配置类中的对象;
private RestHighLevelClient client;
//删除索引请求
public void deleteIndex() throws Exception {
//DeleteIndexRequest()方法参数: 要删除的索引名,返回一个删除索引请求对象;
DeleteIndexRequest request = new DeleteIndexRequest("wsm");
//client的方法执行删除,参数: 删除索引请求对象 RequestOptions.DEFAULT 返回一个Response响应对象;
AcknowledgedResponse delete = client.indices().delete(request, RequestOptions.DEFAULT);
//返回结果true/false 失败/成功!
System.out.println(delete.isAcknowledged());
}
}
主程序测试:
- 控制台返回:true/false
创建索引库/映射
6.0之后一个索引对应一个映射so: 建索引同时加映射;
- 创建索引库put请求
http://localhost:9200/索引库名称
需要设置分片/配置 - 创建映射
post http://localhost:9200/索引库名称/映射名称(类型,表)/_mapping
指定映射名,JSON的所需参数
EsService.Java
@Service
public class EsService {
@Autowired
//RestHighLevelClien REST高级客户端对象,并自动映射配置类中的对象;
private RestHighLevelClient client;
//创建索引库,6.0之后一个索引对应一个映射so: 建索引同时加映射;
public void createIndex() throws Exception {
//创建索引请求对象————指定索引名
CreateIndexRequest request = new CreateIndexRequest("wsm");
//指定分片/备份
request.settings(Settings.builder().put("number_of_shards", "1").put("number_of_replicas", "0"));
//设置映射————类型名,fieid及属性类型...,JSON形式传输
request.mapping("doc", "{n"
"t"properties": {n"
"tt"description": {n"
"ttt"type": "text",n"
"ttt"analyzer": "ik_max_word",n"
"ttt"search_analyzer": "ik_smart"n"
"tt},n"
"tt"name": {n"
"ttt"type": "text",n"
"ttt"analyzer": "ik_max_word",n"
"ttt"search_analyzer": "ik_smart"n"
"tt},n"
"tt"pic": {n"
"ttt"type": "text",n"
"ttt"index": falsen"
"tt},n"
"tt"price": {n"
"ttt"type": "float"n"
"tt},n"
"tt"studymodel": {n"
"ttt"type": "keyword"n"
"tt},n"
"tt"timestamp": {n"
"ttt"type": "date",n"
"ttt"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd"n"
"tt}n"
"t}n"
"}", XContentType.JSON);
//clientindices().create执行创建!—————— 请求参数,DEFAULT.
CreateIndexResponse createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT);
//获取创建结果:boolean
boolean acknowledged = createIndexResponse.isAcknowledged();
System.out.println(acknowledged);
}
}
主程序测试:
- 控制台返回:true
Postaman get查看创建成功!
添加文档 / 根据id修改文档
- post 或 put 请求:
http://localhost:9200/索引名/映射名/id值
传入JSON 参数形式,赋值生成一个Document如果不指定id值ES会自动生成一个唯一ID
添加后的文档,再次执行,指定id 就可以直接修改数据了!
EsService.Java
@Service
public class EsService {
@Autowired
//RestHighLevelClien REST高级客户端对象,并自动映射配置类中的对象;
private RestHighLevelClient client;
//新增文档! 添加数据!
public void addDoc() throws Exception {
//创建一个map类型存储要存储的数据,准备json数据
Map<String, Object> jsonMap = new HashMap<>();
jsonMap.put("name", "spring cloud实战");
jsonMap.put("description", "本课程主要从四个章节进行讲解: 1.微服务架构入门 2.spring cloud基础入门 3.实战Spring Boot 4.注册中心eureka。");
jsonMap.put("studymodel", "201001");
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
jsonMap.put("timestamp", dateFormat.format(new Date()));
jsonMap.put("price", 5.6f);
//索引请求对象————索引名,映射名,id(这里没有添加,相同的id会修改覆盖之前的文档数据!)
IndexRequest request = new IndexRequest("wsm", "doc");
//索引请求对象:内部会转换成JSON
request.source(jsonMap); //存储参数数据,Object类型,这里是Map
//索引响应对象
IndexResponse response = client.index(request, RequestOptions.DEFAULT);
//获取响应结果
DocWriteResponse.Result result = response.getResult();
System.out.println(result);
}
}
主程序测试:
- Get请求:
http://localhost:9200/索引名/映射名/id值
或http://localhost:9200/索引名/映射名/_search
查询所有数据!
- id, 不指定默认提供!
id 查看文档数据
- Get请求:
http://localhost:9200/索引名/映射名/id值
EsService.Java
@Service
public class EsService {
@Autowired
//RestHighLevelClien REST高级客户端对象,并自动映射配置类中的对象;
private RestHighLevelClient client;
//根据 id查询文档数据!
public void getInfo() throws Exception {
//根据索引名,文档名,id值: 获取文档数据
GetRequest request = new GetRequest("wsm", "doc", "W8Q3FngBedCFzRwGU3V0");
GetResponse response = client.get(request, RequestOptions.DEFAULT);
System.out.println(response.isExists()); //isExists() 响应中是否存在数据!
Map<String, Object> sourceAsMap = response.getSourceAsMap(); //返回Map对象,直接输出打印
System.out.println(sourceAsMap);
}
}
主程序测试:
- 控制台输出数据!
更新文档值
- post请求:
http://localhost:9200/索引名/映射/修改文档id/_update
{
"doc" : {
"修改Fieid" : "修改值..."
}
}
- 修改成功:_version版本 1;
EsService.Java
@Service
public class EsService {
@Autowired
//RestHighLevelClien REST高级客户端对象,并自动映射配置类中的对象;
private RestHighLevelClient client;
//更新文档
public void update() throws Exception {
//指定 索引 映射 更新_id
UpdateRequest request = new UpdateRequest("wsm", "doc", "XcRgFngBedCFzRwGanV-");
//要更新的值
Map<String, Object> jsonMap = new HashMap<>();
jsonMap.put("name", "spring boot实战");
//要更新的值存入请求对象中;
request.doc(jsonMap);
//更新
UpdateResponse update = client.update(request, RequestOptions.DEFAULT);
System.out.println(update.status());
}
}
主程序测试:
- 控制台不报错,返回ok
- Postman get查看数据:
- 值更改!
中间出了个意味,重新增了个数据id 重新生成了
常用查询案例:
前言:
- 搜索引擎最关键的就是要搜索结果,因此要有强大的查询能力!
- 为了方便操作,学习,下面一个操作案例资源:
准备环境
- 创建xc_course索引库
Put请求
http://localhost:9200/xc_course
别忘了分片/备份; - 创建映射 Post
http://localhost:9200/xc_course/doc/_mapping
映射的 JSON数据
{
"properties": {
"description": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
},
"name": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
},
"pic": {
"type": "text",
"index": false
},
"price": {
"type": "float"
},
"studymodel": {
"type": "keyword"
},
"timestamp": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
}
}
}
插入数据:post/put
代码语言:javascript复制http://localhost:9200/xc_course/doc/1
{
"name": "Bootstrap开发",
"description": "Bootstrap是由Twitter推出的一个前台页面开发框架,是一个非常流行的开发框架,此框架集成了 多种页面效果。此开发框架包含了大量的CSS、JS程序代码,可以帮助开发者(尤其是不擅长页面开发的程序人员)轻松 的实现一个不受浏览器限制的精美界面效果。",
"studymodel": "201002",
"price": 68.6,
"timestamp": "2018-04-25 19:11:35",
"pic": "group1/M00/00/00/wKhlQFs6RCeAY0pHAAJx5ZjNDEM428.jpg"
}
http://localhost:9200/xc_course/doc/2
{
"name": "java编程基础",
"description": "java语言是世界第一编程语言,在软件开发领域使用人数最多。",
"studymodel": "201002",
"price": 68.6,
"timestamp": "2018-04-25 19:11:35",
"pic": "group1/M00/00/00/wKhlQFs6RCeAY0pHAAJx5ZjNDEM428.jpg"
}
http://localhost:9200/xc_course/doc/3
{
"name": "spring开发基础",
"description": "spring 在java领域非常流行,java程序员都在用。",
"studymodel": "201001",
"price": 88.6,
"timestamp": "2018-04-25 19:11:35",
"pic": "group1/M00/00/00/wKhlQFs6RCeAY0pHAAJx5ZjNDEM428.jpg"
}
查询所有文档
- Get请求
http://localhost:9200/xc_course/doc/_search
- Post请求:
http://localhost:9200/xc_course/doc/_search
Post JSON数据
//post 请求,可以加入很多的条件...实现:分页,条件,多条件...等高级查询;
{
"query": {
"match_all": {}
}
}
EsService.Java
@Service
public class EsService {
@Autowired
//RestHighLevelClien REST高级客户端对象,并自动映射配置类中的对象;
private RestHighLevelClient client;
//查询全部数据
public void testSearchAll ()throws Exception{
//SearchRequest用于与搜索文档、聚合、定制查询有关的任何操作,还提供了在查询结果的基于上,对于匹配的关键词进行突出显示的方法。
SearchRequest searchRequest = new SearchRequest("xc_course"); //指定查询的索引
searchRequest.types("doc"); //指定查询的 映射;
//执行查询的构造对象
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//指定查询的方式;
searchSourceBuilder.query(QueryBuilders.matchAllQuery());
//Source源字段的过滤,指定查询的fieid,相当于: select 列1,列2... 指定查询的列;
searchSourceBuilder.fetchSource(new String[]{"name","description"}, new String[]{});
//完善请求数据:传入构造对象;
searchRequest.source(searchSourceBuilder);
// client发送请求! 获取响应数据Response
SearchResponse searchResponse = client.search(searchRequest , RequestOptions.DEFAULT);
//获取到hits 属性属性
SearchHits hits = searchResponse.getHits();
SearchHit[] searchHits = hits.getHits();
//循环遍历数组,渠道数据!打印输出!全部数据!
System.out.println(searchHits);
for (SearchHit hit : searchHits) {
System.out.println(hit.getIndex());
System.out.println(hit.getId());
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
String name = (String) sourceAsMap.get("name");
String studymodel = (String) sourceAsMap.get("description");
System.out.println(name "t" studymodel "t" sourceAsMap);
}
};
}
主程序测试:
- 结果只有
name
description
- 感谢大佬总结的图文资料:
分页查询
- post请求:
http://localhost:9200/xc_course/doc/_search
JSON参数
代码语言:javascript复制{
"from": 0, //起始文档的下标,从0开始.
"size": 1, //查询的文档数量
"query": {
"match_all": {}
},
"_source": ["name", "studymodel"] //指定查询fieid
}
- from size _source 与query同级!
EsService.Java
@Service
public class EsService {
@Autowired
//RestHighLevelClien REST高级客户端对象,并自动映射配置类中的对象;
private RestHighLevelClient client;
//分页查询数据
public void queryPage() throws Exception {
SearchRequest request = new SearchRequest("xc_course");
request.types("doc");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//设置
int index = 1;
int size = 2;
searchSourceBuilder.from((index - 1) * size); //设置起始位置
searchSourceBuilder.size(size); //设置查询的个数!
searchSourceBuilder.query(QueryBuilders.matchAllQuery());
searchSourceBuilder.fetchSource(new String[]{"name", "studymodel"}, new String[]{});
//包装完整的请求对象
request.source(searchSourceBuilder);
//发起请求获取响应
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
SearchHits searchHits = response.getHits();
//省略输出数据!
}
}
精准Term
查询 Query
- 在搜索时,不会进行
关键词拆分
整体进入数据库查询 精准查询 - post请求:
http://localhost:9200/xc_course/doc/_search
{
"query": {
//term:设置精准查询;
"term": {
"name": "java" //name 精确值Java相当于: like %_% 但值必须得是,分词表的值;
}
}
}
EsService.Java
@Service
public class EsService {
@Autowired
//RestHighLevelClien REST高级客户端对象,并自动映射配置类中的对象;
private RestHighLevelClient client;
//精准查询
public void termAll() throws Exception {
SearchRequest request = new SearchRequest("xc_course");
request.types("doc");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//指定查询的方式termQuery 精准查询参数
//注意QueryBuilders.termQuery 只支持单参精确查;
searchSourceBuilder.query(QueryBuilders.termQuery("studymodel", "201001"));
//包装完整的请求对象
request.source(searchSourceBuilder);
//发起请求获取响应
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
SearchHits searchHits = response.getHits();
//省略输出代码...
}
}
根据id精确匹配
- post请求:
http://localhost:9200/xc_course/doc/_search
{
"query": {
//ids 设置id 请求查询...
"ids": {
"type": "doc", //指定映射类型
"values": "1" //查询id 的值,可以使用 ["1", "2", "3"] 多选条件查,类似于in []
}
}
}
EsService.Java
@Service
public class EsService {
@Autowired
//RestHighLevelClien REST高级客户端对象,并自动映射配置类中的对象;
private RestHighLevelClient client;
/*in查询*/
public void inSearch() throws Exception {
SearchRequest request = new SearchRequest("xc_course");
request.types("doc");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//设置ids,in []条件
String[] ids = {"2", "3"};
//指定查询的方式
searchSourceBuilder.query(QueryBuilders.termsQuery("_id", ids));
//包装完整的请求对象
request.source(searchSourceBuilder);
//发起请求获取响应
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
SearchHits searchHits = response.getHits();
//省略输出代码...
}
}
分词match
查询 Query
minimum_should_match占比查:
- post请求:
http://localhost:9200/xc_course/doc/_search
{
"query": {
//match:分词规则
"match": {
//某个fieid的查询分词...
"description": {
"query": "spring框架", //搜索查询的参数,对其进行拆分,去与文档进行匹配!
"operator": "or", //or:拆分的词只要有一个成立就符合条件 and:拆分词都在文档中出现则才符合条件`精确查询`
"minimum_should_match": "80%"
//,"minimum_should_match": "80%": minimum_should_match指定文档匹配分词占比%
//operator=or表示只要有一个词匹配上就得分, 实现三个词至少有两个词匹配如何实现:
//"minimum_should_match": "80%"表示: 3个词在文档的匹配占比为80%: 3*0.8=2.4 ≈2;(至少有两个词在文档中要匹配成功)
}
}
}
}
- 页面输出,spring框架, Elasticearch将其进行拆分,
Spring
框架
- or 只要查询文档中匹配一个分词就符合条件,and 查询文档中词都要匹配才符合条件;
EsService.Java
@Service
public class EsService {
@Autowired
//RestHighLevelClien REST高级客户端对象,并自动映射配置类中的对象;
private RestHighLevelClient client;
/*分词查询*/
public void matchSearch() throws Exception {
SearchRequest request = new SearchRequest("xc_course");
request.types("doc");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//指定查询的方式,不需要设置% 直接不.即可!
searchSourceBuilder.query(QueryBuilders.matchQuery("description", "spring开发框架").operator(Operator.OR).minimumShouldMatch("80%"));
//包装完整的请求对象
request.source(searchSourceBuilder);
//发起请求获取响应
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
SearchHits searchHits = response.getHits();
//省略....
}
}
多Fieid分词查:
- 普通的分词查询只支持,单个Fieid 的分词查询,multiQuery支持多个Fieid的分词查询
- 对搜索参数进行拆分, 与多个Fieid 进行分词匹配, 还可以通过 boots来划分分词Fieid的
权重
- post请求:
http://localhost:9200/xc_course/doc/_search
{
"query": {
//多Fieid分词查规则;
"multi_match": {
//搜索框....
"query": "spring框架",
"minimum_should_match": "50%",
//指定的多个 Fieid, ^设置权重;
"fields": ["name", "description^10"]
}
}
}
EsService.Java
@Service
public class EsService {
@Autowired
//RestHighLevelClien REST高级客户端对象,并自动映射配置类中的对象;
private RestHighLevelClient client;
//多字段分词查询
public void mutilMatchSearch() throws Exception {
SearchRequest request = new SearchRequest("xc_course");
request.types("doc");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//指定查询的方式: 搜索数据 多个Fieid or 80% name列设置权重10
searchSourceBuilder.query(QueryBuilders.multiMatchQuery("spring css", "description", "name").operator(Operator.OR).minimumShouldMatch("80%").field("name", 10));
//包装完整的请求对象
request.source(searchSourceBuilder);
//发起请求获取响应
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
SearchHits searchHits = response.getHits();
//省略....
}
}
boolean查询,多条件查询:
- post请求:
http://localhost:9200/xc_course/doc/_search
- must 表示必须,多个查询条件必须都满足.
- should 表示或者,多个查询条件只要有一个满足即可
- must_not 表示非
{
"query": {
//bool:实现多条件查;
"bool": {
//must: bool的多条件规则,另外还有:should must_no; (数组内部可以防止多个条件的规则)
"must": [{
//多列的分词查询
"multi_match": {
"query": "spring框架",
"minimum_should_match": "50%",
"fields": ["name^10", "description"]
}
}, {
//精准查询规则
"term": {
"studymodel": "201002"
}
}]
}
}
}
- 省略更多…需要深入发掘!
EsService.Java
@Service
public class EsService {
@Autowired
//RestHighLevelClien REST高级客户端对象,并自动映射配置类中的对象;
private RestHighLevelClient client;
//Bool多条件查询
public void boolSearch() throws Exception {
SearchRequest request = new SearchRequest("xc_course");
request.types("doc");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//设置多字段的分词查询对象
MultiMatchQueryBuilder matchQueryBuilder = QueryBuilders.multiMatchQuery("spring框架", "description", "name").operator(Operator.OR).minimumShouldMatch("80%").field("name", 10);
//设置精准查询对象
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("studymodel", "201001");
//创建多条件对象,并将规则条件传入bool中
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.must(matchQueryBuilder);
boolQueryBuilder.must(termQueryBuilder);
//指定查询的方式
searchSourceBuilder.query(boolQueryBuilder);
//指定查询的Fieid
searchSourceBuilder.fetchSource(new String[]{"name", "studymodel", "description"}, new String[]{});
//包装完整的请求对象
request.source(searchSourceBuilder);
//发起请求获取响应
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
SearchHits searchHits = response.getHits();
//....
}
}
过虑器 filter
范围查 range
- post请求:
http://localhost:9200/xc_course/doc/_search
- 过虑查:
是针对搜索的结果进行过虑,
所以首先要有一个条件查询之后的结果集
对结果集进行的二次查询判断; 因为Filter的过滤操作是在内存中完成的
相比Elasticearch 更快 - range 范围查
范围过虑,保留大于等于 x 并且小于等于 y 的记录。
注意:
range和term一次只能对一个Field设置范围过虑
多个就创建多个, range | term
{
"_source": ["name", "studymodel", "description", "price"],
"query": {
"bool": {
"must": [{
//多列的分词查询,查询后的条件给过滤,进行内存条件判断;
"multi_match": {
"query": "spring框架",
"minimum_should_match": "50%",
"fields": ["name^10", "description"]
}
}],
//过滤规则数组
"filter": [{
//详细过滤: studymodel列的精确值过滤;
"term": {
"studymodel": "201001"
}
}, {
//范围查: price范围过滤查 77
"range": {
"price": {
"gte": 60, //大于等于
"lte": 100 //小于等于
}
}
}]
}
}
}
EsService.Java
@Service
public class EsService {
@Autowired
//RestHighLevelClien REST高级客户端对象,并自动映射配置类中的对象;
private RestHighLevelClient client;
/*过滤条件查询*/
public void filterSearch() throws Exception {
SearchRequest request = new SearchRequest("xc_course");
request.types("doc");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//多字段的分词查询
MultiMatchQueryBuilder matchQueryBuilder = QueryBuilders.multiMatchQuery("spring框架", "description", "name").operator(Operator.OR).minimumShouldMatch("80%").field("name", 10);
//精准查询
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("studymodel", "201001");
//范围查询
RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("price").gte(60).lte(100);
//创建多条件对象
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.must(matchQueryBuilder);
boolQueryBuilder.filter(termQueryBuilder);
boolQueryBuilder.filter(rangeQueryBuilder);
//指定查询的方式
searchSourceBuilder.query(boolQueryBuilder);
//包装完整的请求对象
request.source(searchSourceBuilder);
//发起请求获取响应
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
SearchHits searchHits = response.getHits();
System.out.println(searchHits.totalHits);
SearchHit[] hits = searchHits.getHits();
//...
}
}
排序
- post请求:
http://localhost:9200/xc_course/doc/_search
{
"query": {
"match_all": {}
},
//排序规则数组:内部可以指定多列进行排序; (同级!)
"sort": [{
"studymodel": "desc" //升序
}, {
"price": "asc" //降序
}]
}
EsService.Java
@Service
public class EsService {
@Autowired
//RestHighLevelClien REST高级客户端对象,并自动映射配置类中的对象;
private RestHighLevelClient client;
//排序查询
public void orderSearch() throws Exception {
SearchRequest request = new SearchRequest("xc_course");
request.types("doc");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//设置排序规则
searchSourceBuilder.sort(new FieldSortBuilder("studymodel").order(SortOrder.DESC));
searchSourceBuilder.sort(new FieldSortBuilder("price").order(SortOrder.ASC));
//包装完整的请求对象
request.source(searchSourceBuilder);
//发起请求获取响应
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
SearchHits searchHits = response.getHits();
//...
}
}
高亮显示
- 高亮显示可以将搜索结果一个或多个字突出显示,以便向用户展示匹配关键字的位置。
搭配分词使用, 使分词查看的数据,
突出显示
- post请求:
http://localhost:9200/xc_course/doc/_search
{
"query": {
"bool": {
"must": [{
"multi_match": {
"query": "开发框架",
"minimum_should_match": "50%",
"fields": ["name^10", "description"],
"type": "best_fields"
}
}]
}
},
//高亮显示规则,搭配分词使用:
"highlight": {
//设置分词数据的前缀
"pre_tags": ["<span style=’color:red;’>"],
//设置分词数据的后缀
"post_tags": ["</span>"],
//要进行高亮的 fieid列...
"fields": {
"name": {},
"description": {}
}
}
}
EsService.Java
@Service
public class EsService {
@Autowired
//RestHighLevelClien REST高级客户端对象,并自动映射配置类中的对象;
private RestHighLevelClient client;
//高亮查询查询
public void highlightSearch() throws Exception {
SearchRequest request = new SearchRequest("xc_course");
request.types("doc");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//多字段的分词查询
MultiMatchQueryBuilder matchQueryBuilder = QueryBuilders.multiMatchQuery("spring框架", "description", "name").operator(Operator.OR).minimumShouldMatch("80%").field("name", 10);
//创建多条件对象
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.must(matchQueryBuilder);
//指定查询规则
searchSourceBuilder.query(boolQueryBuilder);
//配置高亮: 分词前缀,后缀,
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.preTags("<span style='color;red;'>");
highlightBuilder.postTags("</span>");
highlightBuilder.fields().add(new HighlightBuilder.Field("name"));
highlightBuilder.fields().add(new HighlightBuilder.Field("description"));
searchSourceBuilder.highlighter(highlightBuilder);
//包装完整的请求对象
request.source(searchSourceBuilder);
//发起请求获取响应
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//....
SearchHits searchHits = response.getHits(); //第一个hits
SearchHit[] hits = searchHits.getHits(); //第二个hits数组,遍历;
for (SearchHit hit : hits) {
//获取原始数据输出....
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
String name = (String) sourceAsMap.get("name"); //获取源数据的name
//获取高亮对象,数据输出...
Map<String, HighlightField> fields = hit.getHighlightFields();
if (fields != null) {
HighlightField nameField = fields.get("name"); //获取name值返回,HighlightField ————>转换成Text数组
if(nameField==null){ //非空判断!
continue; //退出本次循环;
}
Text[] nameTxt = nameField.fragments();
StringBuffer nameSbf = new StringBuffer();
for (Text text : nameTxt) {
nameSbf.append(text.toString());
}
name = nameSbf.toString();
System.out.println("------------------------------");
}
String studymodel = (String) sourceAsMap.get("description");
System.out.println(name "t" studymodel "t" sourceAsMap);
}
}
测试:
分组:
- 向关系型数据库一样:Elasticearch也支持分组,指定某列进行分组…
获取某一个的各个唯一值:
Select 分组列 From 表 order by 分组列 desc/asc;
实例代码.Java
@Autowired
//RestHighLevelClien REST高级客户端对象,并自动映射配置类中的对象;
private RestHighLevelClient client;
//分组
@GetMapping("/order")
public List<String>order() throws Exception {
//指定:索引/映射
SearchRequest request = new SearchRequest("wsm");
request.types("houst");
//创建构造对象;
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//构建设置分组: 设置分组别名——分组列——指定获取分组结果集数量;
searchSourceBuilder.aggregation(AggregationBuilders.terms("typeidGroup").field("typeid").size(2));
//放入请求中去!
request.source(searchSourceBuilder);
//请求
SearchResponse search = client.search(request, RequestOptions.DEFAULT);
//获取分组数据
Terms categoryGroup = search.getAggregations().get("typeidGroup"); //与别名对应,返回分组的数据;!
//处理分组后的数据;
List<String> cateList = termsAsList(categoryGroup);
return cateList;
}
//遍历分组数据——获取List<String>集合
public List<String> termsAsList(Terms terms) {
List<String> list = new ArrayList<>();
//遍历分组数据:
for (int i = 0; i < terms.getBuckets().size(); i ) {
//获取单个分组数据,存进list中;
String str = terms.getBuckets().get(i).getKey().toString();
list.add(str);
}
return list;
}
- 当然分组,还可以搭配其它条件进行分组。
对条件判断之后返回的结果集进行
分组处理
常用场景:
- 京东商品的,品牌/类型/spec规格:
- 因为商品的数量/种类/规格/款式 是非常多的而且,不停更新的所以,商城商品页面的数据都是灵活多变,的数据库数据!
- 可以通过分组,给商品进行分组,品牌进行分组…就可以获取不同商品的多个不同的品牌… 如果是箱子,根据箱子进行查询,分组品牌即可获得所有的箱子匹配进行动态的数据展示!
- 规格:请借鉴下面代码:
分组JSON数据处理:
代码语言:javascript复制 //分组查询: 的数据是唯一的...
//返回类型: 基于,Map: key唯一,set数据也是唯一的!
public Map<String, Set> termsAdMap(Terms terms) {
Map<String, Set> specMap = new HashMap<>();
Set<String> specSet = new HashSet<>();
//循环每一条分组之后的集合数据!存入set中,确保了存入的JSON是唯一的... (因为分组数据本就是唯一的,这个可以省略,但为了方便下面的循环遍历...)
for (int i = 0; i < terms.getBuckets().size(); i ) {
String str = terms.getBuckets().get(i).getKeyAsString();
specSet.add(str);
}
//遍历set
for (String specStr : specSet) {
//将一个个JSON转换成Map对象, {'颜色': '红色', '版本': '8GB 128GB'}————————>Map等于: key value
Map<String, String> map = JSON.parseObject(specStr, Map.class);
//遍历map
for (Map.Entry<String, String> entry : map.entrySet()) { //第一次循环↓↓↓
//获取key value
String key = entry.getKey(); //颜色
String value = entry.getValue(); //红色
//获取集合中是否存储规格: 颜色,没有就创建一个;
Set set = specMap.get(key);
if (set == null) {
set = new HashSet();
}
set.add(value); //将值增进行,如果红色已经存在, set 后面覆盖前面!
//将新的规格数据,添加至 specMap
specMap.put(key, set);
}
}
return specMap;
}
- 实现: