搭建工程
ES提供多种不同的客户端:
1、TransportClient
ES提供的传统客户端,官方计划8.0版本删除此客户端。
2、RestClient
RestClient是官方推荐使用的,它包括两种:Java Low Level REST Client和 Java High Level REST Client。
ES在6.0之后提供 Java High Level REST Client, 两种客户端官方更推荐使用 Java High Level REST Client,不过当
前它还处于完善中,有些功能还没有。
我们采用SpringBoot2.x与ElasticSearch集成
Maven依赖
部分依赖
<properties >
<project.build.sourceEncoding > UTF-8</project.build.sourceEncoding >
<project.reporting.outputEncoding > UTF-8</project.reporting.outputEncoding >
<java.version > 1.8</java.version >
<elasticsearch.version > 6.3.2</elasticsearch.version >
</properties >
<dependencies >
<dependency >
<groupId > org.elasticsearch.client</groupId >
<artifactId > transport</artifactId >
<version > ${elasticsearch.version}</version >
</dependency >
<dependency >
<groupId > org.elasticsearch.client</groupId >
<artifactId > elasticsearch-rest-high-level-client</artifactId >
<version > ${elasticsearch.version}</version >
</dependency >
<dependency >
<groupId > org.elasticsearch</groupId >
<artifactId > elasticsearch</artifactId >
<version > ${elasticsearch.version}</version >
</dependency >
<dependencies >
application.properties
anshe.elasticsearch.hostlist =${eshostlist:你的IP地址:9200}
配置类
package com.anshe.common.config.es;
import com.anshe.web.service.ISearchService;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.net.InetAddress;
@Configuration
public class ElasticsearchConfig {
private static final Logger logger = LoggerFactory.getLogger(ISearchService.class);
@Value("${anshe.elasticsearch.hostlist}")
private String hostlist;
@Bean
public RestHighLevelClient restHighLevelClient () {
String[] split = hostlist.split("," );
HttpHost[] httpHostArray = new HttpHost [split.length];
for (int i=0 ;i<split.length;i++){
String item = split[i];
httpHostArray[i] = new HttpHost (item.split(":" )[0 ], Integer.parseInt(item.split(":" )[1 ]), "http" );
}
return new RestHighLevelClient (RestClient.builder(httpHostArray));
}
@Bean
public RestClient restClient () {
String[] split = hostlist.split("," );
HttpHost[] httpHostArray = new HttpHost [split.length];
for (int i=0 ;i<split.length;i++){
String item = split[i];
httpHostArray[i] = new HttpHost (item.split(":" )[0 ], Integer.parseInt(item.split(":" )[1 ]), "http" );
}
return RestClient.builder(httpHostArray).build();
}
@Bean(name = "transportClient")
public TransportClient transportClient () {
logger.info("Elasticsearch初始化开始。。。。。" );
TransportClient transportClient = null ;
try {
Settings esSetting = Settings.builder()
.put("cluster.name" , "elasticsearch_anshe" )
.put("client.transport.sniff" , true )
.build();
transportClient = new PreBuiltTransportClient (esSetting);
TransportAddress transportAddress = new TransportAddress (InetAddress.getByName("你的IP地址" ), 9300 );
transportClient.addTransportAddresses(transportAddress);
} catch (Exception e) {
logger.error("elasticsearch TransportClient create error!!" , e);
}
return transportClient;
}
}
主启动类
package com.anshe ;
import org.springframework .boot .SpringApplication ;
import org.springframework .boot .autoconfigure .SpringBootApplication ;
import tk.mybatis .spring .annotation .MapperScan ;
@SpringBootApplication
@MapperScan (basePackages = "com.anshe.web.mapper" )
public class AnsheApplication {
public static void main (String [] args ) {
System .setProperty ("es.set.netty.runtime.available.processors" , "false" );
SpringApplication .run (AnsheApplication .class , args);
}
}
索引管理
创建索引库
API
创建索引:
put http://localhost:9200/索引名称
{
"settings" :{
"index" :{
"number_of_shards" :"1" ,
"number_of_replicas" :"0"
}
}
}
创建映射:
发送:put http://localhost:9200/索引库名称/类型名称/_mapping
创建类型为xc_course的映射,共包括三个字段:name、description、studymodel 等
http://localhost:9200/xc_course/doc/_mapping
{
"properties" : {
"name" : {
"type" : "text" ,
"analyzer" : "ik_max_word" ,
"search_analyzer" : "ik_smart"
} ,
"description" : {
"type" : "text" ,
"analyzer" : "ik_max_word" ,
"search_analyzer" : "ik_smart"
} ,
"studymodel" : {
"type" : "keyword"
} ,
"price" : {
"type" : "float"
} ,
"timestamp" : {
"type" : "date" ,
"format" : "yyyy‐MM‐dd HH:mm:ss||yyyy‐MM‐dd||epoch_millis"
}
}
}
Java客户端
@Autowired
RestHighLevelClient client;
@Autowired
RestClient restClient;
@Test
public void testCreateIndex() throws IOException {
CreateIndexRequest createIndexRequest = new CreateIndexRequest ("xc_course" );
createIndexRequest.settings(Settings .builder().put("number_of_shards" ,"1" ).put("number_of_replicas" ,"0" ));
createIndexRequest.mapping("doc" ," {\n " +
" \t \" properties\" : {\n " +
" \" studymodel\" :{\n " +
" \" type\" :\" keyword\" \n " +
" },\n " +
" \" name\" :{\n " +
" \" type\" :\" keyword\" \n " +
" },\n " +
" \" description\" : {\n " +
" \" type\" : \" text\" ,\n " +
" \" analyzer\" :\" ik_max_word\" ,\n " +
" \" search_analyzer\" :\" ik_smart\" \n " +
" },\n " +
" \" pic\" :{\n " +
" \" type\" :\" text\" ,\n " +
" \" index\" :false\n " +
" }\n " +
" \t }\n " +
"}" , XContentType .JSON );
IndicesClient indices = client.indices();
CreateIndexResponse createIndexResponse = indices.create(createIndexRequest);
boolean acknowledged = createIndexResponse.isAcknowledged();
System .out.println(acknowledged);
}
删除索引库
API
DELETE http://['你自己的Ip加Port' ]/test
{
"acknowledged" : true
}
Java客户端
@Test
public void testDeleteIndex () throws IOException {
DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest ("xc_course" );
IndicesClient indices = client.indices();
DeleteIndexResponse delete = indices.delete(deleteIndexRequest);
boolean acknowledged = delete.isAcknowledged();
System.out.println(acknowledged);
}
添加文档
API
格式如下: PUT /{index}/{type}/{id} { “fifield”: “value”, … }
如果不指定id,ES会自动生成。
一个例子:
put http://localhost:9200/xc_course/doc/3
{
"name" : "spring cloud实战" ,
"description" : "本课程主要从四个章节进行讲解: 1.微服务架构入门 2.spring cloud 基础入门 3.实战Spring Boot 4.注册中心eureka。" ,
"studymodel" : "201001" ,
"price" : 5.6
}
Java客户端
@Test
public void testAddDoc () throws IOException {
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 );
IndexRequest indexRequest = new IndexRequest ("xc_course" ,"doc" );
indexRequest.source(jsonMap);
IndexResponse indexResponse = client.index(indexRequest);
DocWriteResponse.Result result = indexResponse.getResult();
System.out.println(result);
}
查询文档
API
格式如下: GET /{index}/{type}/{id}
Java客户端
@Test
public void testGetDoc () throws IOException {
GetRequest getRequest = new GetRequest ("xc_course" ,"doc" ,"0fOCF2sBEYTsNRZ43I8b" );
GetResponse getResponse = client.get(getRequest);
Map<String, Object> sourceAsMap = getResponse.getSourceAsMap();
System.out.println(sourceAsMap);
}
更新文档
API
ES更新文档的顺序是:先检索到文档、将原来的文档标记为删除、创建新文档、删除旧文档,创建新文档就会重建
索引。
通过请求Url有两种方法:
1、完全替换
Post:http://localhost:9200/xc_test/doc/3
{
"name" : "spring cloud实战" ,
"description" : "本课程主要从四个章节进行讲解: 1.微服务架构入门 2.spring cloud 基础入门 3.实战SpringBoot 4.注册中心eureka。" ,
"studymodel" : "201001" ,
"price" : 5.6
}
2、局部更新
下边的例子是只更新price字段。
post: http://localhost:9200/xc_test/doc/3/_update
{
"doc" : {
"price" : 66.6
}
}
Java客户端
使用 Client Api更新文档的方法同上边第二种局部更新方法。
可以指定文档的部分字段也可以指定完整的文档内容。
@Test public void updateDoc () throws IOException {
UpdateRequest updateRequest = new UpdateRequest ("xc_course" , "doc" , "4028e581617f945f01617f9dabc40000" );
Map<String, String> map = new HashMap <>();
map.put("name" , "spring cloud实战" );
updateRequest.doc(map);
UpdateResponse update = client.update(updateRequest);
RestStatus status = update.status();
System.out.println(status);
}
删除文档
API
1、根据id删除,格式如下:
DELETE /{index}/{type}/{id}
2、搜索匹配删除,将搜索出来的记录删除,格式如下:
POST /{index}/{type}/_delete_by_query
下边是搜索条件例子:
{
"query" : {
"term" : {
"studymodel" : "201001"
}
}
}
上边例子的搜索匹配删除会将studymodel为201001的记录全部删除
Java客户端
@Test
public void testDelDoc () throws IOException {
String id = "eqP_amQBKsGOdwJ4fHiC" ;
DeleteRequest deleteRequest = new DeleteRequest ("xc_course" ,"doc" ,id);
DeleteResponse deleteResponse = client.delete(deleteRequest);
DocWriteResponse.Result result = deleteResponse.getResult();
System.out.println(result);
}
搜索匹配删除还没有具体的api,可以采用先搜索出文档id,根据文档id删除。
—–下面是DSL搜索的内容—–
DSL搜索环境准备
创建映射
创建xc_course索引库。
创建如下映射
post:http://localhost:9200/xc_course/doc/_mapping
{
"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"
}
}
}
插入原始数据
向xc_course/doc中插入以下数据:
http://localhost:9200/xc_course/doc/1
{
"name" : "Bootstrap开发" ,
"description" : "Bootstrap是由Twitter推出的一个前台页面开发框架,是一个非常流行的开发框架,此框架集成了 多种页面效果。此开发框架包含了大量的CSS、JS程序代码,可以帮助开发者(尤其是不擅长页面开发的程序人员)轻松 的实现一个不受浏览器限制的精美界面效果。" ,
"studymodel" : "201002" ,
"price" : 38.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" : "201001" ,
"price" : 68.6,
"timestamp" : "2018‐03‐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‐02‐24 19:11:35" ,
"pic" : "group1/M00/00/00/wKhlQFs6RCeAY0pHAAJx5ZjNDEM428.jpg"
}
DSL(Domain Specifific Language)是ES提出的基于json的搜索方式,在搜索时传入特定的json格式的数据来完成不 同的搜索需求。 DSL比URI搜索方式功能强大,在项目中建议使用DSL方式来完成搜索。
查询所有文档
API
查询所有索引库的文档。
发送:post http://localhost:9200/_search
查询指定索引库指定类型下的文档。(通过使用此方法)
发送:post http://localhost:9200/xc_course/doc/_search
{
"query" : {
"match_all" : { }
} ,
"_source" : [
"name" ,
"studymodel"
]
}
_source:source源过虑设置,指定结果中所包括的字段有哪些。
结果说明:
took:本次操作花费的时间,单位为毫秒。
timed_out:请求是否超时
_shards:说明本次操作共搜索了哪些分片
hits:搜索命中的记录
hits.total : 符合条件的文档总数 hits.hits :匹配度较高的前N个文档
hits.max_score:文档匹配得分,这里为最高分
_score:每个文档都有一个匹配度得分,按照降序排列。
_source:显示了文档的原始内容。
Java客户端
@Autowired
RestHighLevelClient client;
@Autowired
RestClient restClient;
@Test
public void testSearchAll () throws IOException, ParseException {
SearchRequest searchRequest = new SearchRequest ("xc_course" );
searchRequest.types("doc" );
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder ();
searchSourceBuilder.query(QueryBuilders.matchAllQuery());
searchSourceBuilder.fetchSource(new String []{"name" ,"studymodel" ,"price" ,"timestamp" },new String []{});
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = client.search(searchRequest);
SearchHits hits = searchResponse.getHits();
long totalHits = hits.getTotalHits();
SearchHit[] searchHits = hits.getHits();
SimpleDateFormat dateFormat = new SimpleDateFormat ("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" );
for (SearchHit hit:searchHits){
String id = hit.getId();
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
String name = (String) sourceAsMap.get("name" );
String description = (String) sourceAsMap.get("description" );
String studymodel = (String) sourceAsMap.get("studymodel" );
Double price = (Double) sourceAsMap.get("price" );
Date timestamp = dateFormat.parse((String) sourceAsMap.get("timestamp" ));
System.out.println(name);
System.out.println(studymodel);
System.out.println(description);
}
}
分页查询
API
ES支持分页查询,传入两个参数:from和size。
form:表示起始文档的下标,从0开始。
size:查询的文档数量。
发送:post http://localhost:9200/xc_course/doc/_search
{
"from ": 0 ,
"size" : 1 ,
"query" : {
"match_all": {}
},
"_source": [
"name" ,
"studymodel"
]
}
Java客户端
@Test
public void testSearchPage () throws IOException, ParseException {
SearchRequest searchRequest = new SearchRequest ("xc_course" );
searchRequest.types("doc" );
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder ();
int page = 1 ;
int size = 1 ;
int from = (page-1 )*size;
searchSourceBuilder.from(from);
searchSourceBuilder.size(size);
searchSourceBuilder.query(QueryBuilders.matchAllQuery());
searchSourceBuilder.fetchSource(new String []{"name" ,"studymodel" ,"price" ,"timestamp" },new String []{});
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = client.search(searchRequest);
SearchHits hits = searchResponse.getHits();
long totalHits = hits.getTotalHits();
SearchHit[] searchHits = hits.getHits();
SimpleDateFormat dateFormat = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss" );
for (SearchHit hit:searchHits){
String id = hit.getId();
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
String name = (String) sourceAsMap.get("name" );
String description = (String) sourceAsMap.get("description" );
String studymodel = (String) sourceAsMap.get("studymodel" );
Double price = (Double) sourceAsMap.get("price" );
Date timestamp = dateFormat.parse((String) sourceAsMap.get("timestamp" ));
System.out.println(name);
System.out.println(studymodel);
System.out.println(description);
}
}
Term Query
API
Term Query为精确查询,在搜索时会整体匹配关键字,不再将关键字分词。
发送:post http://localhost:9200/xc_course/doc/_search
{
"query" : {
"term" : {
"name" : "spring"
}
} ,
"_source" : [
"name" ,
"studymodel"
]
}
上边的搜索会查询name包括“spring”这个词的文档。
Java客户端
@Test
public void testTermQuery () throws IOException, ParseException {
SearchRequest searchRequest = new SearchRequest ("xc_course" );
searchRequest.types("doc" );
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder ();
int page = 1 ;
int size = 1 ;
int from = (page-1 )*size;
searchSourceBuilder.from(from);
searchSourceBuilder.size(size);
searchSourceBuilder.query(QueryBuilders.termQuery("name" ,"spring" ));
searchSourceBuilder.fetchSource(new String []{"name" ,"studymodel" ,"price" ,"timestamp" },new String []{});
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = client.search(searchRequest);
SearchHits hits = searchResponse.getHits();
long totalHits = hits.getTotalHits();
SearchHit[] searchHits = hits.getHits();
SimpleDateFormat dateFormat = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss" );
for (SearchHit hit:searchHits){
String id = hit.getId();
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
String name = (String) sourceAsMap.get("name" );
String description = (String) sourceAsMap.get("description" );
String studymodel = (String) sourceAsMap.get("studymodel" );
Double price = (Double) sourceAsMap.get("price" );
Date timestamp = dateFormat.parse((String) sourceAsMap.get("timestamp" ));
System.out.println(name);
System.out.println(studymodel);
System.out.println(description);
}
}
根据id精确匹配
API
ES提供根据多个id值匹配的方法:
测试:
post: http://127.0.0.1:9200/xc_course/doc/_search
{
"query" : {
"ids" : {
"type" : "doc" ,
"values" : [
"3" ,
"4" ,
"100"
]
}
}
}
Java客户端
@Test
public void testTermQueryByIds () throws IOException, ParseException {
SearchRequest searchRequest = new SearchRequest ("xc_course" );
searchRequest.types("doc" );
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder ();
String[] ids = new String []{"1" ,"2" };
searchSourceBuilder.query(QueryBuilders.termsQuery("_id" ,ids));
searchSourceBuilder.fetchSource(new String []{"name" ,"studymodel" ,"price" ,"timestamp" },new String []{});
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = client.search(searchRequest);
SearchHits hits = searchResponse.getHits();
long totalHits = hits.getTotalHits();
SearchHit[] searchHits = hits.getHits();
SimpleDateFormat dateFormat = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss" );
for (SearchHit hit:searchHits){
String id = hit.getId();
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
String name = (String) sourceAsMap.get("name" );
String description = (String) sourceAsMap.get("description" );
String studymodel = (String) sourceAsMap.get("studymodel" );
Double price = (Double) sourceAsMap.get("price" );
Date timestamp = dateFormat.parse((String) sourceAsMap.get("timestamp" ));
System.out.println(name);
System.out.println(studymodel);
System.out.println(description);
}
}
match Query
API
match Query即全文检索,它的搜索方式是先将搜索字符串分词,再使用各各词条从索引中搜索。
match query与Term query区别是match query在搜索前先将搜索关键字分词,再拿各各词语去索引中搜索。
发送:post http://localhost:9200/xc_course/doc/_search
{
"query" : {
"match" : {
"description" : {
"query" : "spring开发" ,
"operator" : "or"
}
}
}
}
query:搜索的关键字,对于英文关键字如果有多个单词则中间要用半角逗号分隔,而对于中文关键字中间可以用
逗号分隔也可以不用。
operator:or 表示 只要有一个词在文档中出现则就符合条件,and表示每个词都在文档中出现则才符合条件。
上边的搜索的执行过程是:
1、将“spring开发”分词,分为spring、开发两个词
2、再使用spring和开发两个词去匹配索引中搜索。
3、由于设置了operator为or,只要有一个词匹配成功则就返回该文档。
Java客户端
@Test
public void testMatchQuery () throws IOException, ParseException {
SearchRequest searchRequest = new SearchRequest ("xc_course" );
searchRequest.types("doc" );
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder ();
searchSourceBuilder.query(QueryBuilders.matchQuery("description" ,"spring开发框架" )
.minimumShouldMatch("80%" ));
searchSourceBuilder.fetchSource(new String []{"name" ,"studymodel" ,"price" ,"timestamp" },new String []{});
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = client.search(searchRequest);
SearchHits hits = searchResponse.getHits();
long totalHits = hits.getTotalHits();
SearchHit[] searchHits = hits.getHits();
SimpleDateFormat dateFormat = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss" );
for (SearchHit hit:searchHits){
String id = hit.getId();
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
String name = (String) sourceAsMap.get("name" );
String description = (String) sourceAsMap.get("description" );
String studymodel = (String) sourceAsMap.get("studymodel" );
Double price = (Double) sourceAsMap.get("price" );
Date timestamp = dateFormat.parse((String) sourceAsMap.get("timestamp" ));
System.out.println(name);
System.out.println(studymodel);
System.out.println(description);
}
}
multi Query
API
1、基本使用
上边学习的termQuery和matchQuery一次只能匹配一个Field,本节学习multiQuery,一次可以匹配多个字段。
单项匹配是在一个fifield中去匹配,多项匹配是拿关键字去多个Field中匹配。
例子:
发送:post http://localhost:9200/xc_course/doc/_search
拿关键字 “spring css”去匹配name 和description字段。
{
"query" : {
"multi_match" : {
"query" : "spring css" ,
"minimum_should_match" : "50%" ,
"fields" : [
"name" ,
"description"
]
}
}
}
2、提升boost
匹配多个字段时可以提升字段的boost(权重)来提高得分
例子:
提升boost之前,执行下边的查询:
{
"query" : {
"multi_match" : {
"query" : "spring框架" ,
"minimum_should_match" : "50%" ,
"fields" : [
"name" ,
"description"
]
}
}
}
通过查询发现Bootstrap排在前边。
提升boost,通常关键字匹配上name的权重要比匹配上description的权重高,这里可以对name的权重提升
{
"query" : {
"multi_match" : {
"query" : "spring框架" ,
"minimum_should_match" : "50%" ,
"fields" : [
"name^10" ,
"description"
]
}
}
}
“name^10” 表示权重提升10倍,执行上边的查询,发现name中包括spring关键字的文档排在前边。
Java客户端
@Test
public void testMultiMatchQuery () throws IOException, ParseException {
SearchRequest searchRequest = new SearchRequest ("xc_course" );
searchRequest.types("doc" );
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder ();
searchSourceBuilder.query(QueryBuilders.multiMatchQuery("spring css" ,"name" ,"description" )
.minimumShouldMatch("50%" )
.field("name" ,10 ));
searchSourceBuilder.fetchSource(new String []{"name" ,"studymodel" ,"price" ,"timestamp" },new String []{});
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = client.search(searchRequest);
SearchHits hits = searchResponse.getHits();
long totalHits = hits.getTotalHits();
SearchHit[] searchHits = hits.getHits();
SimpleDateFormat dateFormat = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss" );
for (SearchHit hit:searchHits){
String id = hit.getId();
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
String name = (String) sourceAsMap.get("name" );
String description = (String) sourceAsMap.get("description" );
String studymodel = (String) sourceAsMap.get("studymodel" );
Double price = (Double) sourceAsMap.get("price" );
Date timestamp = dateFormat.parse((String) sourceAsMap.get("timestamp" ));
System.out.println(name);
System.out.println(studymodel);
System.out.println(description);
}
}
布尔查询
API
布尔查询对应于Lucene的BooleanQuery查询,实现将多个查询组合起来。
三个参数:
must:文档必须匹配must所包括的查询条件,相当于 “AND”
should:文档应该匹配should所包括的查询条件其中的一个或多个,相当于 “OR”
must_not:文档不能匹配must_not所包括的该查询条件,相当于“NOT”
分别使用must、should、must_not测试下边的查询:
发送:POST http://localhost:9200/xc_course/doc/_search
{
"_source" : [
"name" ,
"studymodel" ,
"description"
] ,
"from" : 0 ,
"size" : 1 ,
"query" : {
"bool" : {
"must" : [
{
"multi_match" : {
"query" : "spring框架" ,
"minimum_should_match" : "50%" ,
"fields" : [
"name^10" ,
"description"
]
}
} ,
{
"term" : {
"studymodel" : "201001"
}
}
]
}
}
}
must:表示必须,多个查询条件必须都满足。(通常使用must)
should:表示或者,多个查询条件只要有一个满足即可。
must_not:表示非。
Java客户端
@Test
public void testBoolQuery () throws IOException, ParseException {
SearchRequest searchRequest = new SearchRequest ("xc_course" );
searchRequest.types("doc" );
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder ();
MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("spring css" , "name" , "description" )
.minimumShouldMatch("50%" )
.field("name" , 10 );
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("studymodel" , "201001" );
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.must(multiMatchQueryBuilder);
boolQueryBuilder.must(termQueryBuilder);
searchSourceBuilder.query(boolQueryBuilder);
searchSourceBuilder.fetchSource(new String []{"name" ,"studymodel" ,"price" ,"timestamp" },new String []{});
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = client.search(searchRequest);
SearchHits hits = searchResponse.getHits();
long totalHits = hits.getTotalHits();
SearchHit[] searchHits = hits.getHits();
SimpleDateFormat dateFormat = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss" );
for (SearchHit hit:searchHits){
String id = hit.getId();
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
String name = (String) sourceAsMap.get("name" );
String description = (String) sourceAsMap.get("description" );
String studymodel = (String) sourceAsMap.get("studymodel" );
Double price = (Double) sourceAsMap.get("price" );
Date timestamp = dateFormat.parse((String) sourceAsMap.get("timestamp" ));
System.out.println(name);
System.out.println(studymodel);
System.out.println(description);
}
}
过虑器
API
过虑是针对搜索的结果进行过虑,过虑器主要判断的是文档是否匹配,不去计算和判断文档的匹配度得分,所以过 虑器性能比查询要高,且方便缓存,推荐尽量使用过虑器去实现查询或者过虑器和查询共同使用。 过虑器在布尔查询中使用,下边是在搜索结果的基础上进行过虑:
{
"_source": [
"name" ,
"studymodel" ,
"description" ,
"price"
],
"query" : {
"bool": {
"must": [
{
"multi_match": {
"query": "spring框架" ,
"minimum_should_match" : "50%" ,
"fields" : [
"name^10" ,
"description"
]
}
}
],
"filter ": [
{
"term": {
"studymodel": "201001"
}
},
{
"range": {
"price": {
"gte": 60 ,
"lte" : 100
}
}
}
]
}
}
}
range:范围过虑,保留大于等于60 并且小于等于100的记录。
term:项匹配过虑,保留studymodel等于”201001”的记录。
注意:range和term一次只能对一个Field设置范围过虑。
Java客户端
@Test
public void testFilter () throws IOException, ParseException {
SearchRequest searchRequest = new SearchRequest ("xc_course" );
searchRequest.types("doc" );
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder ();
MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("spring css" , "name" , "description" )
.minimumShouldMatch("50%" )
.field("name" , 10 );
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.must(multiMatchQueryBuilder);
boolQueryBuilder.filter(QueryBuilders.termQuery("studymodel" ,"201001" ));
boolQueryBuilder.filter(QueryBuilders.rangeQuery("price" ).gte(90 ).lte(100 ));
searchSourceBuilder.query(boolQueryBuilder);
searchSourceBuilder.fetchSource(new String []{"name" ,"studymodel" ,"price" ,"timestamp" },new String []{});
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = client.search(searchRequest);
SearchHits hits = searchResponse.getHits();
long totalHits = hits.getTotalHits();
SearchHit[] searchHits = hits.getHits();
SimpleDateFormat dateFormat = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss" );
for (SearchHit hit:searchHits){
String id = hit.getId();
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
String name = (String) sourceAsMap.get("name" );
String description = (String) sourceAsMap.get("description" );
String studymodel = (String) sourceAsMap.get("studymodel" );
Double price = (Double) sourceAsMap.get("price" );
Date timestamp = dateFormat.parse((String) sourceAsMap.get("timestamp" ));
System.out.println(name);
System.out.println(studymodel);
System.out.println(description);
}
}
排序
API
可以在字段上添加一个或多个排序,支持在keyword、date、flfloat等类型上添加,text类型的字段上不允许添加排
序。
发送 POST http://localhost:9200/xc_course/doc/_search
过虑0–10元价格范围的文档,并且对结果进行排序,先按studymodel降序,再按价格升序
{
"_source": [
"name" ,
"studymodel" ,
"description" ,
"price"
],
"query" : {
"bool": {
"filter ": [
{
"range": {
"price": {
"gte": 0 ,
"lte" : 100
}
}
}
]
}
},
"sort": [
{
"studymodel": "desc"
},
{
"price": "asc"
}
]
}
Java客户端
@Test
public void testSort () throws IOException, ParseException {
SearchRequest searchRequest = new SearchRequest ("xc_course" );
searchRequest.types("doc" );
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder ();
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.filter(QueryBuilders.rangeQuery("price" ).gte(0 ).lte(100 ));
searchSourceBuilder.query(boolQueryBuilder);
searchSourceBuilder.sort("studymodel" , SortOrder.DESC);
searchSourceBuilder.sort("price" , SortOrder.ASC);
searchSourceBuilder.fetchSource(new String []{"name" ,"studymodel" ,"price" ,"timestamp" },new String []{});
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = client.search(searchRequest);
SearchHits hits = searchResponse.getHits();
long totalHits = hits.getTotalHits();
SearchHit[] searchHits = hits.getHits();
SimpleDateFormat dateFormat = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss" );
for (SearchHit hit:searchHits){
String id = hit.getId();
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
String name = (String) sourceAsMap.get("name" );
String description = (String) sourceAsMap.get("description" );
String studymodel = (String) sourceAsMap.get("studymodel" );
Double price = (Double) sourceAsMap.get("price" );
Date timestamp = dateFormat.parse((String) sourceAsMap.get("timestamp" ));
System.out.println(name);
System.out.println(studymodel);
System.out.println(description);
}
}
高亮显示
API
高亮显示可以将搜索结果一个或多个字突出显示,以便向用户展示匹配关键字的位置。
在搜索语句中添加highlight即可实现,如下:
Post: http://127.0.0.1:9200/xc_course/doc/_search
{
"_source": [
"name" ,
"studymodel" ,
"description" ,
"price"
],
"query" : {
"bool": {
"must": [
{
"multi_match": {
"query": "开发框架" ,
"minimum_should_match" : "50%" ,
"fields" : [
"name^10" ,
"description"
],
"type" : "best_fields"
}
}
],
"filter ": [
{
"range": {
"price": {
"gte": 0 ,
"lte" : 100
}
}
}
]
}
},
"sort": [
{
"price": "asc"
}
],
"highlight": {
"pre_tags": [
"<tag1>"
],
"post_tags" : [
"</tag2>"
],
"fields" : {
"name": {},
"description": {}
}
}
}
Java客户端
@Test
public void testHighlight () throws IOException, ParseException {
SearchRequest searchRequest = new SearchRequest ("xc_course" );
searchRequest.types("doc" );
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder ();
MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("开发框架" , "name" , "description" )
.minimumShouldMatch("50%" )
.field("name" , 10 );
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.must(multiMatchQueryBuilder);
boolQueryBuilder.filter(QueryBuilders.rangeQuery("price" ).gte(0 ).lte(100 ));
searchSourceBuilder.query(boolQueryBuilder);
searchSourceBuilder.fetchSource(new String []{"name" ,"studymodel" ,"price" ,"timestamp" },new String []{});
HighlightBuilder highlightBuilder = new HighlightBuilder ();
highlightBuilder.preTags("<tag>" );
highlightBuilder.postTags("</tag>" );
highlightBuilder.fields().add(new HighlightBuilder .Field("name" ));
highlightBuilder.fields().add(new HighlightBuilder .Field("description" ));
searchSourceBuilder.highlighter(highlightBuilder);
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = client.search(searchRequest);
SearchHits hits = searchResponse.getHits();
long totalHits = hits.getTotalHits();
SearchHit[] searchHits = hits.getHits();
SimpleDateFormat dateFormat = new SimpleDateFormat ("yyyy-MM-dd'T'HH:mm:ss.SSS Z" );
for (SearchHit hit:searchHits){
String id = hit.getId();
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
String name = (String) sourceAsMap.get("name" );
Map<String, HighlightField> highlightFields = hit.getHighlightFields();
if (highlightFields!=null ){
HighlightField nameHighlightField = highlightFields.get("name" );
if (nameHighlightField!=null ){
Text[] fragments = nameHighlightField.getFragments();
StringBuffer stringBuffer = new StringBuffer ();
for (Text text:fragments){
stringBuffer.append(text);
}
name = stringBuffer.toString();
}
}
String description = (String) sourceAsMap.get("description" );
String studymodel = (String) sourceAsMap.get("studymodel" );
Double price = (Double) sourceAsMap.get("price" );
Date timestamp = dateFormat.parse((String) sourceAsMap.get("timestamp" ));
System.out.println(name);
System.out.println(studymodel);
System.out.println(description);
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?