JDK最低要求1.8,elasticsearch、kibana、logstash和elasticsearch-analysis-ik分词器他们的版本号一致,我这用的7.8.0
一、ElasticSearch安装
/elasticsearch-7.8.0
├── config # 配置文件
│ └── elasticsearch.yml # es的默认配置文件,比如启动端口,跨域访问配置等
│ └── jvm.options # es启动时,jvm设置的参数,比如默认运行内存1G
├── data # 数据存放目录
├── lib # 启动需要的jar包
├── plugins # 插件存放目录
│ └── ik # ik分词器
│ └── config # ik分词器配置文件目录
│ └── IKAnalyzer.cfg.xml # ik分词器配置文件目录
前往bin文件下运行elasticsearch.bat,在网页访问http://localhost:9200/默认地址,可看见下面界面,说明安装成功了
2、跨域配置(config目录下elasticsearch.yml)
http.cors.enabled: true
http.cors.allow-origin: "*"
node.master: true
node.data: true
二、安装ik分词器
1、下载地址 https://github.com/medcl/elasticsearch-analysis-ik/releases
2、解压后复制到es目录下plugins,并且先新建ik目录,在进行粘贴,如图
3、IKAnalyzer.cfg.xml的内容,在这里可以自定义自己的分词字段,修改后一定要从重启es才能生效
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>IK Analyzer 扩展配置</comment>
<!--用户可以在这里配置自己的扩展字典 -->
<entry key="ext_dict"></entry>
<!--用户可以在这里配置自己的扩展停止词字典-->
<entry key="ext_stopwords"></entry>
<!--用户可以在这里配置远程扩展字典 -->
<!-- <entry key="remote_ext_dict">words_location</entry> -->
<!--用户可以在这里配置远程扩展停止词字典-->
<!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>
三、elasticsearch-head
前提需要安装node
git clone git://github.com/mobz/elasticsearch-head.git
cd elasticsearch-head
# 安装依赖包
npm install
npm run start
# 浏览器访问地址
open http://localhost:9100/
修改项目中Gruntfile.js文件
connect: {
server: {
options: {
host:'*', #新增内容
port: 9100,
base: '.',
keepalive: true
}
}
}
四、安装kibana
1、解压kibana 后的目录
前往bin文件下启动kibana.bat,在网页访问http://localhost:9200/默认地址,可看见下面界面,说明安装成功了
?2、汉化
找到目录下config中的kibana.yml打开
# 默认英文
i18n.locale: "en"
# 修改为zh-CN,保存然后重启
i18n.locale: "zh-CN"
?重新进入http://localhost:5601/ 可见到下面中文界面,说明成功
?
?进入控制台
http://localhost:5601/app/kibana#/dev_tools/console
?
?插入一个文档数据?
POST /school/student/
{"name":"coleman","birth":"1998-01-12","interest":"唱歌,跳舞"}
POST /school/student/
{"name":"perry","birth":"1991-05-12","interest":"唱歌,写bug,阅读"}
POST /school/student/
{"name":"sky","birth":"1995-08-17","interest":"老色痞,听音乐,阅读"}
POST /school/student/
{"name":"tom","birth":"1998-01-12","interest":"足球,听音乐"}
POST /school/student/
{"name":"witt","birth":"1993-12-01","interest":"阅读,听音乐"}
?在head页面中查看结果
?
?查看school索引结构
?
?五、Java代码测试ES是否能连接成功并获取数据
package com.example.demo;
import org.apache.http.HttpHost;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import java.io.IOException;
public class TestMain {
public static void main(String[] args) throws IOException {
//创建对象,设置集群名称和IP地址
RestHighLevelClient es = new RestHighLevelClient(
RestClient.builder(new HttpHost("127.0.0.1",9200,"http")));
String indexName = "school";//索引名称
String typeName = "student";//类型名称
//搜索全部文档
QueryBuilder queryBuilder = QueryBuilders.matchAllQuery();
SearchRequest searchRequest=new SearchRequest(indexName);
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(queryBuilder);
SearchResponse searchResponse = es.search(searchRequest, RequestOptions.DEFAULT);
SearchHits hits = searchResponse.getHits();
SearchHit[] searchHits = hits.getHits();
int i = 0;
for (SearchHit searchHit : searchHits) {
String name = (String) searchHit.getSourceAsMap().get("name");
String birth = (String) searchHit.getSourceAsMap().get("birth");
String interest = (String) searchHit.getSourceAsMap().get("interest");
System.out.println("-------------" + (++i) + "------------");
System.out.println(name);
System.out.println(birth);
System.out.println(interest);
}
}
}
?运行可以顺利看到我们刚才通过kibana顺利写入的数据
?
?六、DSL增删改查
6.1、GET查看索引下面的所有数据
# 语法格式
GET /{index}/_search
# 示例
GET /school/_search
# 结果
{
"took" : 811,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 5,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "school",
"_type" : "student",
"_id" : "F9c-BXcB-0z8APitc9eo",
"_score" : 1.0,
"_source" : {
"name" : "perry",
"birth" : "1991-05-12",
"interest" : "唱歌,写bug,阅读"
}
},
{
"_index" : "school",
"_type" : "student",
"_id" : "HNc-BXcB-0z8APitn9dw",
"_score" : 1.0,
"_source" : {
"name" : "sky",
"birth" : "1995-08-17",
"interest" : "老色痞,听音乐,阅读"
}
},
{
"_index" : "school",
"_type" : "student",
"_id" : "H9c-BXcB-0z8APitt9eG",
"_score" : 1.0,
"_source" : {
"name" : "tom",
"birth" : "1998-01-12",
"interest" : "足球,听音乐"
}
},
{
"_index" : "school",
"_type" : "student",
"_id" : "Itc-BXcB-0z8APitytcU",
"_score" : 1.0,
"_source" : {
"name" : "witt",
"birth" : "1993-12-01",
"interest" : "阅读,听音乐"
}
},
{
"_index" : "school",
"_type" : "student",
"_id" : "Cdc9BXcB-0z8APit8Ncm",
"_score" : 1.0,
"_source" : {
"name" : "witt",
"birth" : "1993-12-01",
"interest" : "唱歌 跳舞"
}
}
]
}
}
6.2、GET通过Id查找单个数据
# 检索API
GET /{index}/_doc/{id}
# 示例
GET school/_doc/F9c-BXcB-0z8APitc9eo
# 结果
{
"_index" : "school",
"_type" : "_doc",
"_id" : "F9c-BXcB-0z8APitc9eo", # 被查询的Id
"_version" : 1, # 被修改的次数
"_seq_no" : 1,
"_primary_term" : 1,
"found" : true,
"_source" : {
"name" : "perry",
"birth" : "1991-05-12",
"interest" : "唱歌,写bug,阅读"
}
}
6.3、POST新增数据?
# 语法
POST /{index}/_doc/
# demo
POST /school/_doc/
{
"name" : "UZI",
"birth" : "1995-12-21",
"interest" : "打游戏"
}
# 返货结果
{
"_index" : "school",
"_type" : "_doc",
"_id" : "Ab-wGHcBSmS4p2_9zsWY",
"_version" : 1,
"result" : "created", #创建了索引
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 12,
"_primary_term" : 5
}
head中查看到了结果
?
?6.4、POST更新Index字段(未指定的字段会被置空)
# 检索Api
POST /{index}/_doc/{id}
# 示例
POST /school/_doc/HNc-BXcB-0z8APitn9dw
{
"interest" : "唱歌 背锅"
}
# 结果
{
"_index" : "school",
"_type" : "_doc",
"_id" : "HNc-BXcB-0z8APitn9dw",
"_version" : 2,
"result" : "updated",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 14,
"_primary_term" : 5
}
更新后结果?
?6.5、PUT更新Index字段(未指定的字段会被置空)?
# 检索API
PUT /{index}/_doc/{id}
# 示例
PUT /school/_doc/F9c-BXcB-0z8APitc9eo
{
"interest" : "rap饶舌歌手"
}
# 结果
{
"_index" : "school",
"_type" : "_doc",
"_id" : "F9c-BXcB-0z8APitc9eo", # 被更新的Id
"_version" : 2, # 更新后版本加1
"result" : "updated", # 返回已更新
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 13,
"_primary_term" : 5
}
?更新前?
?更新后?
?6.5.1、小结
通过POST、PUT更新Index字段,发现如果只想修改指定的字段会失败,没有被赋值的字段旧值会被置空
6.6、更新文档?
通过POST和_update, 更新文档中的特定字段(field), 其他的字段不会改动。与替换方式相比, 更新方式的好处: 可以更新指定文档的指定field, 未指定的field也不会丢失.
# 检索DSL
POST /{index}/_update/{id}
{
"doc": {
"field u want to update": "new value of ur update's field"
}
}
# 获取一个文档
GET school/_doc/HNc-BXcB-0z8APitn9dw
#结果
{
"_index" : "school",
"_type" : "_doc",
"_id" : "HNc-BXcB-0z8APitn9dw",
"_version" : 6,
"_seq_no" : 18,
"_primary_term" : 5,
"found" : true,
"_source" : {
"name" : "sky",
"birth" : "1998-07-21",
"interest" : "唱歌 背锅"
}
}
#更新birth字段
POST /school/_update/HNc-BXcB-0z8APitn9dw
{
"doc": {
"birth": "2012-07-21"
}
}
#结果
{
"_index" : "school",
"_type" : "_doc",
"_id" : "HNc-BXcB-0z8APitn9dw",
"_version" : 9,
"result" : "updated",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 21,
"_primary_term" : 5
}
# 再次查询,验证结果无误
{
"_index" : "school",
"_type" : "_doc",
"_id" : "HNc-BXcB-0z8APitn9dw",
"_version" : 9,
"_seq_no" : 21,
"_primary_term" : 5,
"found" : true,
"_source" : {
"name" : "sky",
"birth" : "2015-07-21",
"interest" : "唱歌 背锅"
}
}
?6.7、删除文档?
#DSL语法
DELETE /{index}/_doc/{id}
# 示例
DELETE /school/_doc/Ob91GHcBSmS4p2_9b7_7
# 结果
{
"_index" : "school",
"_type" : "_doc",
"_id" : "F9c-BXcB-0z8APitc9eo",
"_version" : 3,
"result" : "deleted", # 删除结果
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 22,
"_primary_term" : 5
}
?6.8、分页查询,字段高亮,指定搜索返货的字段?
# DSL语法
GET /{index}/_search
# 示例
GET school/_search
{
"from": 0, # 第一页
"size": 10, # 每页数据大小
"highlight": { # 高亮字段
"fields": {"name": {}}
},
"query": {
"match": {"name": "sky"} #查询
},
"_source": ["birth","name"] #指定只返回birth和name字段
}
# 结果
"hits" : [
{
"_index" : "school",
"_type" : "student",
"_id" : "HNc-BXcB-0z8APitn9dw",
"_score" : 1.1631508,
"_source" : { # 只返回birth和name字段
"name" : "sky",
"birth" : "2015-07-21"
},
"highlight" : {
"name" : [ #给匹配拆分后的查询词增加高亮的 html 标签
"<em>sky</em>"
]
}
}
]
?6.9、精确匹配
在DSL中通过使用match_phrase来精确匹配,不会对查询的字段值进行分词,必须全部相等,才能查出
6.10、范围查询
?
??
# 示例-查询兴趣唱歌的年级在22-26之间
GET /school/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"interest": "唱歌"
}
}
],
"filter": {
"range": {
"age": {
"gte": "22",
"lte": "26"
}
}
}
}
}
}
#hits 结果
"hits" : [
{
"_index" : "school",
"_type" : "student",
"_id" : "Cdc9BXcB-0z8APit8Ncm",
"_score" : 2.059239,
"_source" : {
"name" : "coleman",
"birth" : "1993-12-01",
"interest" : "唱歌 跳舞",
"age" : "26"
}
},
{
"_index" : "school",
"_type" : "student",
"_id" : "HNc-BXcB-0z8APitn9dw",
"_score" : 2.059239,
"_source" : {
"name" : "sky",
"birth" : "2015-07-21",
"interest" : "唱歌 背锅",
"age" : "23"
}
}
]
?6.11、多字段匹配 multi_match?
# multi_match 用来对多个字段同时进行匹配: 任意一个字段中存在相应的分词, 就可作为结果返回.
GET /school/_search
{
"query": {
"multi_match": {
"query": "唱歌",
"fields": ["name","interest"]
}
}
}
#hits结果
"hits" : [
{
"_index" : "school",
"_type" : "student",
"_id" : "Cdc9BXcB-0z8APit8Ncm",
"_score" : 2.059239,
"_source" : {
"name" : "coleman",
"birth" : "1993-12-01",
"interest" : "唱歌 跳舞",
"age" : "26"
}
},
{
"_index" : "school",
"_type" : "student",
"_id" : "HNc-BXcB-0z8APitn9dw",
"_score" : 2.059239,
"_source" : {
"name" : "sky",
"birth" : "2015-07-21",
"interest" : "唱歌 背锅",
"age" : "23"
}
}
]
?????6.12、多条件组合查询?
?bool 查询下面有四个子查询
- must - 必须匹配, 类似于SQL中的 =
- must_not - 必须不匹配, 类似于SQL中的 !=
should - 不强制匹配, 类似于SQL中的 or ,如果组合查询中没有must条件,那should中必须至少匹配一个。我们也还可以通过minimum_should_match来限制匹配更多个
- filter - 过滤, 将满足一定条件的文档筛选出来
GET school/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"age": "22"
}
}
],
"must_not": [
{
"match": {
"interest": "唱歌"
}
}
],
"should": [
{
"match": {
"name": "coleman"
}
}
]
}
}
}
# 結果
"hits" : [
{
"_index" : "school",
"_type" : "student",
"_id" : "Itc-BXcB-0z8APitytcU",
"_score" : 1.3862942,
"_source" : {
"name" : "witt",
"birth" : "1993-12-01",
"interest" : "阅读,听音乐",
"age" : "22"
}
}
]
#结论 有先滿足条件must>must_not>should
6.15、prefix前缀查询?
GET /school/_search
{
"query": {
"prefix": {
"name": {
"value": "c"
}
}
}
}
# 结果
"hits" : [
{
"_index" : "school",
"_type" : "student",
"_id" : "Cdc9BXcB-0z8APit8Ncm",
"_score" : 1.0,
"_source" : {
"name" : "coleman",
"birth" : "1993-12-01",
"interest" : "唱歌 跳舞",
"age" : "26"
}
}
]
七、SpringBoot集成 elasticsearch-rest-high-level-client
7.1、引入maven管理包?
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.8.0</version>
</dependency>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>7.8.0</version>
</dependency>
?application.properties中加入es地址?
elasticsearch.host=localhost
elasticsearch.port=9200
?新建启动配置类?
package com.example.demo;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
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 EsConfiguration {
@Value("${elasticsearch.host}")
private String host;
@Value("${elasticsearch.port}")
private int port;
// @Value("${elastic.username}")
// private String userName;
//
// @Value("${elastic.password}")
// private String password;
@Bean(destroyMethod = "close")
public RestHighLevelClient restHighLevelClient() {
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
// credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(userName, password));
HttpHost httpHost = new HttpHost(host, port, "http");
RestClientBuilder builder = RestClient.builder(httpHost).setRequestConfigCallback(new RestClientBuilder.RequestConfigCallback() {
@Override
public RequestConfig.Builder customizeRequestConfig(RequestConfig.Builder requestConfigBuilder) {
requestConfigBuilder.setConnectTimeout(2000);
requestConfigBuilder.setSocketTimeout(5000);
requestConfigBuilder.setConnectionRequestTimeout(5000);
return requestConfigBuilder;
}
}).setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
@Override
public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {
httpClientBuilder.disableAuthCaching();
return httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
}
});
RestHighLevelClient restHighLevelClient = new RestHighLevelClient(builder);
return restHighLevelClient;
}
}
?7.2、RestHighLevelClient操作es增删改查?
package com.example.demo;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
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.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.stereotype.Repository;
import javax.annotation.Resource;
import java.util.Map;
@Repository
@Slf4j
public class RestHighLevelClientDAOImpl implements EsClientDAO{
@Resource
private RestHighLevelClient restHighLevelClient;
@Override
public IndexResponse insertDocument(String index, String type, Object doc) {
IndexRequest indexRequest = new IndexRequest(index);
//indexRequest.type(type);
indexRequest.source(JSON.toJSONString(doc), XContentType.JSON);
IndexResponse indexResponse = null;
try {
indexResponse = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
} catch (Exception e) {
log.warn("createDocument failure!, parameter index: {}, type:{}, details: {}", index, type, JSON.toJSONString(doc), e);
}
return indexResponse;
}
@Override
public CreateIndexResponse createIndex(String index, String type, Map<String, Object> mapping) {
CreateIndexRequest createIndexRequest = new CreateIndexRequest(index);
createIndexRequest.mapping(type, mapping);
CreateIndexResponse createIndexResponse = null;
try {
createIndexResponse = restHighLevelClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);
} catch (Exception e) {
log.warn("createIndex failure! index: {}, type: {}, mapping: {}", index, type, JSON.toJSONString(mapping), e);
}
return createIndexResponse;
}
@Override
public DeleteResponse deleteIndex(String index) {
DeleteRequest indexRequest = new DeleteRequest(index);
DeleteResponse deleteResponse = null;
try {
deleteResponse = restHighLevelClient.delete(indexRequest, RequestOptions.DEFAULT);
} catch (Exception e) {
log.warn("deleteIndex failure! index: {}", index);
}
return deleteResponse;
}
@Override
public Boolean existsIndex(String index) {
GetIndexRequest request = new GetIndexRequest();
request.indices(index);
boolean exists = false;
try {
exists = restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);
} catch (Exception e) {
log.warn("existsIndex failure! index: {}", index, e);
}
return exists;
}
@Override
public SearchResponse searchDoc(String index, String type, QueryBuilder queryBuilder, AggregationBuilder aggregationBuilder) {
SearchRequest searchRequest = new SearchRequest(index);
searchRequest.types(type);
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchRequest.source(searchSourceBuilder);
searchSourceBuilder.query(queryBuilder);
if (aggregationBuilder != null) {
searchSourceBuilder.aggregation(aggregationBuilder);
}
SearchResponse searchResponse = null;
try {
searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
} catch (Exception e) {
log.warn("searchDoc failure! index: {}, type: {}, queryBuilder: {}, aggBuilder: {}", index, type, queryBuilder, aggregationBuilder, e);
}
return searchResponse;
}
/**
* <=> group by key1, key2
* @param index
* @param key1
* @param key2
* @return
*/
public Map<String, Long> groupByTwice(String index, String type, String key1, String key2) {
SearchRequest searchRequest = new SearchRequest(index);
searchRequest.types(type);
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchRequest.source(searchSourceBuilder);
TermsAggregationBuilder aggregation = AggregationBuilders.terms("by_" + key1)
.field(key1 + ".keyword");
aggregation.subAggregation(AggregationBuilders.terms("by_" + key2)
.field(key2 + ".keyword"));
searchSourceBuilder.aggregation(aggregation);
SearchResponse searchResponse = null;
try {
searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
} catch (Exception e) {
log.warn("serach failure! key1: {}, key2: {}", key1, key2, e);
}
Map<String, Long> map = Maps.newHashMap();
if (searchResponse != null) {
ParsedTerms key1Agg = searchResponse.getAggregations().get("by_" + key1);
for (Terms.Bucket bucket : key1Agg.getBuckets()) {
ParsedTerms key2Agg = bucket.getAggregations().get("by_" + key2);
key2Agg.getBuckets().forEach((bucket1) -> map.put(bucket.getKeyAsString() + "-" + bucket1.getKeyAsString(), bucket1.getDocCount()));
}
}
return map;
}
/**
* <=> where field1 = field1Value group by field2
* @param index
* @param type
* @param field1
* @param field1Value
* @param field2
* @return
*/
public Map<String, Long> selectByField1AndGroupByField2(String index, String type, String field1, String field1Value, String field2) {
SearchRequest searchRequest = new SearchRequest(index);
searchRequest.types(type);
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchRequest.source(searchSourceBuilder);
searchSourceBuilder.query(QueryBuilders.matchQuery(field1, field1Value));
searchSourceBuilder.aggregation(AggregationBuilders.terms("by_" + field2).field(field2));
SearchResponse searchResponse = null;
try {
searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
} catch (Exception e) {
log.warn("serach failure! field1: {}, field1Value: {}, field2: {}", field1, field1Value, field2, e);
}
Map<String, Long> map = Maps.newHashMap();
if (searchResponse != null) {
ParsedTerms field2Agg = searchResponse.getAggregations().get("by_" + field2);
field2Agg.getBuckets().forEach((bucket) -> map.put(bucket.getKeyAsString(), bucket.getDocCount()));
}
return map;
}
/**
* 索引是否存在
* @return
*/
public boolean existIndex(String index) {
GetIndexRequest request = new GetIndexRequest();
request.indices(index);
boolean exists = false;
try {
exists = restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);
} catch (Exception e) {
log.warn("exist failure! index: {}", index, e);
}
return exists;
}
}
?7.3、Java常见简单查询
property:某个属性对应
value:属性的值?
7.3.1、查询单个字段,完全匹配QueryBuilders.termQuery?
# PostMan GET 请求
http://localhost:1000/searchDoc?property=name&value=coleman
# 查询条件
TermQueryBuilder queryBuilder = QueryBuilders.termQuery(property, value);
# 结果
[
{
"name": "coleman",
"birth": "1998-01-12",
"interest": "唱歌,跳舞"
}
]
?7.3.2、查询多个字段,完全匹配QueryBuilders.termsQuery?
#PostMan GET 请求
http://localhost:1000/termsQuery?property=name&value1=coleman&value2=tom
# 查询条件
TermsQueryBuilder queryBuilder = QueryBuilders.termsQuery(property, Arrays.asList(value1,value2));
# 结果
[
{
"name": "coleman",
"birth": "1998-01-12",
"interest": "唱歌,跳舞"
},
{
"name": "tom",
"birth": "1998-01-12",
"interest": "足球,听音乐"
}
]
?7.3.3、 查询多个字段,完全匹配QueryBuilders.matchQuery?
# PostMan GET 请求
http://localhost:1000/matchQuery?property=interest&value=阅读,听音乐
# 查询条件
MatchQueryBuilder queryBuilder = QueryBuilders.matchQuery(property, value);
#结果
[
{
"name": "witt",
"birth": "1993-12-01",
"interest": "阅读,听音乐"
},
{
"name": "sky",
"birth": "1995-08-17",
"interest": "老色痞,听音乐,阅读"
},
{
"name": "tom",
"birth": "1998-01-12",
"interest": "足球,听音乐"
},
{
"name": "perry",
"birth": "1991-05-12",
"interest": "唱歌,写bug,阅读"
}
]
?7.3.4、模糊查询 QueryBuilders.wildcardQuery?
# 模糊查询,?匹配单个字符,*匹配多个字符
# PostMan
http://localhost:1000/wildcardQuery?property=name&value=t
# 查询条件
WildcardQueryBuilder queryBuilder = QueryBuilders.wildcardQuery(property, "*"+value+"*");
#结果
[
{
"name": "witt",
"birth": "1993-12-01",
"interest": "阅读,听音乐"
},
{
"name": "tom",
"birth": "1998-01-12",
"interest": "足球,听音乐"
}
]
?7.3.5、分页,并设置排序字段
fielddata在text字段中默认未启用,需要先先开启,因为fielddata会消耗大量的堆内存,特别是当加载大量的text字段时;fielddata一旦加载到堆中,在segment的生命周期之内都将一致保持在堆中,所以谨慎使用 。经过查证是字段col54类型为Text格式,然后涉及到了聚合排序等功能。没有进行优化,也类似没有加索引。没有优化的字段es默认是禁止聚合/排序操作的
否者查询的时候会报如下错
org.elasticsearch.ElasticsearchException: Elasticsearch exception [type=illegal_argument_exception, reason=Text fields are not optimised for operations that require per-document field data like aggregations and sorting, so these operations are disabled by default. Please use a keyword field instead. Alternatively, set fielddata=true on [age] in order to load field data by uninverting the inverted index. Note that this can use significant memory.]
?
# kibana中开启对应字段的fielddata
# 示例
PUT school/_mapping
{
"properties": {
"age": { # 需要排序的字段
"type": "text",
"fielddata": true #fielddata 设置为true
}
}
}
#执行结果
{
"acknowledged" : true
}
- 模糊查询name字段中有t的数据?
# PostMan 请求
http://localhost:1000/pageQuery?property=name&value=t&from=0
# java代码
SearchRequest searchRequest = new SearchRequest(indexName);
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.wildcardQuery(property, "*"+value+"*"));//和es中term一样匹配
searchSourceBuilder.from(from);
searchSourceBuilder.size(3);
//searchSourceBuilder.sort(new ScoreSortBuilder().order(SortOrder.DESC));
searchSourceBuilder.sort(new FieldSortBuilder("age").order(SortOrder.DESC));
searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
# 执行结果
[
{
"name": "witt",
"birth": "1993-12-01",
"interest": "阅读,听音乐",
"age": 22
},
{
"name": "tom",
"birth": "1998-01-12",
"interest": "足球,听音乐",
"age": 18
}
]
?7.3.5、Count API 统计查询数据
CountRequest countRequest = new CountRequest(index); //这里加索引
//也可以多索引
//countRequest.indices("blog", "author");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.matchAllQuery()); //查询所有
/*SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(QueryBuilders.termQuery("name", "tom"));*/
countRequest.source(searchSourceBuilder);
CountResponse countResponse = client
.count(countRequest, RequestOptions.DEFAULT);
//返回
long count = countResponse.getCount(); # 数据总数
RestStatus status = countResponse.status();
Boolean terminatedEarly = countResponse.isTerminatedEarly();
int totalShards = countResponse.getTotalShards();
int skippedShards = countResponse.getSkippedShards();
int successfulShards = countResponse.getSuccessfulShards();
int failedShards = countResponse.getFailedShards();
for (ShardSearchFailure failure : countResponse.getShardFailures()) {
// failures should be handled here
}
?
本文暂时没有评论,来添加一个吧(●'◡'●)