编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

ELK从入门以及常见api使用(elk接入)

wxchong 2024-07-16 10:52:24 开源技术 8 ℃ 0 评论

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
}

?

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表