elkクライアントとspringbootの統合

一緒に書く習慣を身につけましょう!「ナゲッツデイリーニュープラン・4月アップデートチャレンジ」に参加して11日目です。クリックしてイベントの詳細をご覧ください

上記の調査を通じて、springbootによって出力されたログをelasticsearchに同期したと思います。次に、条件に従ってシステムモジュール内の対応するデータをクエリする必要があります。ここでのブロガーのニーズは比較的単純であり、使用シナリオは単一であるため、春に提供されたスタートがクライアントとして使用されます。統合する方法を以下に説明します。

1.ElasticsearchTemplateクエリ構文

ElasticsearchTemplateを使用する場合は、提供されているAPIをマスターするだけで済みます。以下は、小規模なパートナーが使用するために一般的に使用されるクエリAPIの概要です。

        // 返回对象
        Result<List<ActionLogVO>> result = new Result();
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        BoolQueryBuilder bool = QueryBuilders.boolQuery();
 
 
        //must为and的语法
        //matchPhraseQuery为将type分词 然后将第二个参数匹配 可以模糊查询使用
        bool.must(QueryBuilders.matchPhraseQuery("Type", "日志"));
 
        //wildcardQuery模糊查询使用  但是字段需要未英文 
        bool.must(QueryBuilders.wildcardQuery("userName", "*admin*"));
 
        
        //通过时间筛选
        List<QueryBuilder> filters = bool.filter();                           
        filters.add(QueryBuilders.rangeQuery("time").gte(sd.parse("2021-01-19 17:28:41"))
        .lte(sd.parse("2021-01-19 17:28:43")));
  
 
        //分页(第一个参数PageNum从第0页开始 第二个参数pageSize)
        builder.withPageable(PageRequest.of(1, 10));
 
        //排序
        builder.withSort(SortBuilders.fieldSort("time").order(SortOrder.ASC));
 
 
        // 构造查询条件
        builder.withQuery(bool);
        NativeSearchQuery query = builder.build();
        Iterable<XXXVO> resultIter = XXXXService.search(query);
复制代码

2.条件付きクエリ

1.pomファイルを変更します

        <!-- elasticsearch -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
            <version>2.3.7.RELEASE</version>
        </dependency>
复制代码

2.application.ymlを変更します

spring: 
 elasticsearch:
    rest:
      uris: ip:9200
      #上文安装时配置的账号密码
      username: xxxx      
      password: xxxx
  data:
    elasticsearch:
      repositories:
        enabled: true
      client:
        reactive:
#          username: xxx 这种写法是不对的
#          password: xxx 这种写法是不对的
#          endpoints: ip:9200 这种写法是不对的
          use-ssl: false
复制代码

知らせ:

  1. 構成esアドレスは、家主の場所に書き込む必要があります。そうでない場合、デフォルトでlocalhost:9200になります。esが他のサーバーにインストールされている場合、接続は失敗します。
  2. 古いバージョンの構成とは異なり、開いているポート番号は9200です。

3.新しい構成ファイル

次のファイルが追加されていない場合、java.lang.IllegalStateExceptionが発生します。availableProcessorsはすでに[4]に設定されており、[4]例外を拒否します。

@Configuration
public class ElasticSearchConfig {
    /**
     * 防止netty的bug
     * java.lang.IllegalStateException: availableProcessors is already set to [4], rejecting [4]
     */
    @PostConstruct
    void init() {
        System.setProperty("es.set.netty.runtime.available.processors", "false");
    }
}

复制代码

4.インターフェースの書き込み

主にElasticsearchRestTemplateでAPIを呼び出します。詳細な説明については、以下のコメントを参照してください。

    @Autowired
    ElasticsearchRestTemplate elasticsearchTemplate;

    @Log(operationName = "日志-查询登录日志")
    @PostMapping("/selectLoginLog")
    public Result<List<LoginLogVO>> selectLoginLog(@RequestBody LoginLogInputVO loginLogInputVO) throws ParseException {
        // 日期格式化
        SimpleDateFormat sd = new SimpleDateFormat(DateFormatEnum.YYYY_MM_DD_HH_MM_SS.getFormat());
        // 返回对象
        Result<List<LoginLogVO>> result = new Result();
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        BoolQueryBuilder bool = QueryBuilders.boolQuery();
        // 用户名不为空
        if (!CommonUtil.isEmpty(loginLogInputVO.getUserName())) {
            bool.must(QueryBuilders.wildcardQuery("userName", "*" + loginLogInputVO.getUserName() + "*"));
        }
        // 时间不为空
        if (!CommonUtil.isEmpty(loginLogInputVO.getBeginTime()) && !CommonUtil.isEmpty(loginLogInputVO.getEndTime())) {
            List<QueryBuilder> filters = bool.filter();
            filters.add(QueryBuilders.rangeQuery("time")
                .gte(sd.parse(loginLogInputVO.getBeginTime() + DateFormatEnum.BEGIN_HH_MM_SS.getFormat()))
                .lte(sd.parse(loginLogInputVO.getEndTime() + DateFormatEnum.END_HH_MM_SS.getFormat())));
        }
        // 分页查询
        if (!CommonUtil.isEmpty(loginLogInputVO.getPageSize()) && !CommonUtil.isEmpty(loginLogInputVO.getPageNum())) {
            // 从第0页开始
            builder.withPageable(PageRequest.of(loginLogInputVO.getPageNum() - 1, loginLogInputVO.getPageSize()));
        }
        builder.withSort(SortBuilders.fieldSort("time").order(SortOrder.ASC));
        // 构造查询条件
        builder.withQuery(bool);
        NativeSearchQuery query = builder.build();
        //查询的索引
        IndexCoordinates indexCoordinates = IndexCoordinates.of("loginlog-*");
        //执行查询
        SearchHits<LoginLogVO> resultIter = elasticsearchTemplate.search(query, LoginLogVO.class, indexCoordinates);
        // 格式化输出
        List<LoginLogVO> resultList = new ArrayList<>();
        List<SearchHit<LoginLogVO>> SearchHitList = resultIter.getSearchHits();
        for (SearchHit<LoginLogVO> loginLogVOSearchHit : SearchHitList) {
            resultList.add(loginLogVOSearchHit.getContent());
        }
        // 分页返回
        if (!CommonUtil.isEmpty(loginLogInputVO.getPageSize()) && !CommonUtil.isEmpty(loginLogInputVO.getPageNum())) {
            result.setTotal(resultIter.getTotalHits());
            result.setPageNum(loginLogInputVO.getPageNum());
            result.setPageSize(loginLogInputVO.getPageSize());
        }
        result.setData(resultList);
        return result;
    }
复制代码

ここでのloginlog-*インデックスは、loginlog-で始まるすべてのインデックスを指します。

5.エンティティクラス

1.Elasticsearchクライアントクエリの使用

ElasticsearchTemplate.searchメソッドを実行するときは、特別なエンティティクラスが必要です。

@Document(indexName = "loginlog-*", shards = 1, replicas = 0)
public class LoginLogVO {

    @Id
    private String id;

    /**
     * 信息
     */
    @Field(type = FieldType.Keyword, analyzer = "ik_max_word")
    private String message;

    @Field(type = FieldType.Date, store = true, format = DateFormat.date_time)
    private Date time;
}
复制代码

説明は次のとおりです。

  • @Document:Elasticsearchドキュメントにマップされたドメインオブジェクトを示します。ここで、indexNameはインデックス名を表し、shardsはデフォルトのシャード数を表し、replicasはデフォルトのレプリカ数を表します。
  • @Id:ドキュメントのIDを示し、ドキュメントはmysqlのテーブル行の概念と見なすことができます
  • @Field:ドキュメント内のフィールドのタイプ。アナライザーはトークナイザータイプを表し、formatはフォーマットタイプを表し、タイプタイプにはText(セグメント化およびインデックス付けされる文字タイプ)、Integer、Long、Date、Float、ダブル、ブール待機。

2.POを入力します

共通のエンティティクラスの場合、クエリパラメータを渡します。

public class LoginLogInputVO extends BaseEntity {

    /**
     * 用户账号
     */
    private String userName;

    /**
     * 开始时间
     */
    private String beginTime;

    /**
     * 结束时间
     */
    private String endTime;
}

复制代码

家主のフロントエンドとバックエンドで合意された時間タイプは文字列であるため、タイプを変換してから返す必要があります。

6.注意を払う

ElasticsearchTemplateは、一度に10,000個のアイテムしかクエリできません。したがって、すべてのページを返すことはお勧めしません。次のページング方法を使用することをお勧めします。Baiduを参照してください。ここに画像の説明を挿入

3.時間間隔内にデータをエクスポートします

1.インターフェースの書き込み

    @ApiOperation(value = "导出详细日志接口", notes = "导出详细日志接口")
    @PostMapping("/exportDetailLog")
    public void exportDetailLog(@ApiParam(name = "导出详细日志接口输入参数实体", value = "导出详细日志接口输入参数实体",
        required = false) @RequestBody HandleDetailLogVO handleDetailLogVO) throws IOException, ParseException {
        SimpleDateFormat sd = new SimpleDateFormat(DateFormatEnum.YYYY_MM_DD_HH_MM_SS.getFormat());
        String beginTime = handleDetailLogVO.getBeginTime() + DateFormatEnum.BEGIN_HH_MM_SS.getFormat();
        String endTime = handleDetailLogVO.getEndTime() + DateFormatEnum.END_HH_MM_SS.getFormat();
        String path = handleDetailLogVO.getPath() + "/" + handleDetailLogVO.getBeginTime() + "-"
            + handleDetailLogVO.getEndTime() + ".txt";
        // 根据时间查询
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        BoolQueryBuilder bool = QueryBuilders.boolQuery();
        List<QueryBuilder> filters = bool.filter();
        //构建查询条件
        filters.add(QueryBuilders.rangeQuery("time").gte(sd.parse(beginTime)).lte(sd.parse(endTime)));
        builder.withQuery(bool);
        NativeSearchQuery query = builder.build();
        //查询的索引
        IndexCoordinates indexCoordinates = IndexCoordinates.of("loginlog-*");
        // 查询前1w条
        SearchScrollHits<DetailLogVO> scroll =
            elasticsearchTemplate.searchScrollStart(3000, query, DetailLogVO.class, indexCoordinates);
        List<SearchHit<DetailLogVO>> resultList = new ArrayList<>();
        while (scroll.hasSearchHits()) {
            List<SearchHit<DetailLogVO>> searchHitList = scroll.getSearchHits();
            resultList.addAll(searchHitList);
            scroll = elasticsearchTemplate.searchScrollContinue(scroll.getScrollId(), 3000, DetailLogVO.class,
                indexCoordinates);
        }
        // 导出为text流
        Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path, true), "utf-8"));
        for (int i = 0; i < resultList.size(); i++) {
            out.write(resultList.get(i).getContent().getMessage());
            out.write("\r\n");
        }
        out.flush();
        out.close();
        // 删除索引
        elasticsearchTemplate.delete(query, DetailLogVO.class, indexCoordinates);
    }
复制代码

注:1wのクエリ制限があるため、クエリはループされます。しかし、どこでもログは8gを超えることはできません。

2.エンティティクラス

これは主に、入力パラメータがクエリ時間を運ぶという条件です。

public class HandleDetailLogVO {
 
    /**
     * 结束时间
     */
    @ApiModelProperty(value = "结束时间", name = "结束时间")
    private String endTime;
 
    /**
     * 开始时间
     */
    @ApiModelProperty(value = "开始时间", name = "开始时间")
    private String beginTime;
 
    /**
     * 导出路径
     */
    @ApiModelProperty(value = "导出路径", name = "导出路径")
    private String path;
}
复制代码

4.その期間のデータを削除します

1.インターフェースの書き込み

また、APIを介してその期間のデータを削除します。詳細については、コードコメントを参照してください。

    @ApiOperation(value = "清除详细日志接口", notes = "清除详细日志接口")
    @PostMapping("/clearDetailLog")
    public void clearDetailLog(@ApiParam(name = "清除详细日志接口输入参数实体", value = "清除详细日志接口输入参数实体",
        required = false) @RequestBody HandleDetailLogVO handleDetailLogVO) throws IOException, ParseException {
        SimpleDateFormat sd = new SimpleDateFormat(DateFormatEnum.YYYY_MM_DD_HH_MM_SS.getFormat());
        String beginTime = handleDetailLogVO.getBeginTime() + DateFormatEnum.BEGIN_HH_MM_SS.getFormat();
        String endTime = handleDetailLogVO.getEndTime() + DateFormatEnum.END_HH_MM_SS.getFormat();
        // 根据时间查询
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        BoolQueryBuilder bool = QueryBuilders.boolQuery();
        List<QueryBuilder> filters = bool.filter();
        filters.add(QueryBuilders.rangeQuery("time").gte(sd.parse(beginTime)) .lte(sd.parse(endTime)));
        builder.withQuery(bool);
        //构建查询条件
        NativeSearchQuery query = builder.build();
        //指定删除索引的名称
        IndexCoordinates indexCoordinates = IndexCoordinates.of("datalog-*");
        // 调用API删除索引
        elasticsearchTemplate.delete(query, DetailLogVO.class, indexCoordinates);
    }
复制代码

2.エンティティクラス

クエリ条件を運ぶ入力エンティティ。

public class HandleDetailLogVO {
 
        /**
         * 结束时间
         */
        @ApiModelProperty(value = "结束时间", name = "结束时间")
        private String endTime;
 
        /**
         * 开始时间
         */
        @ApiModelProperty(value = "开始时间", name = "开始时间")
        private String beginTime;
}
复制代码

おすすめ

転載: juejin.im/post/7085352486495584293