springboot+Elasticsearch进阶

package com.admin.model;


import com.fasterxml.jackson.annotation.JsonFormat;
import com.admin.common.entity.BaseSJFZEntity;
import lombok.Data;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;

import java.util.Date;

/**
 * Es 索引库实体
 *
 * @author wangwei
 * @date 2024-04-25
 */

/***
 * esmodel8、 esmodel9 是存储在es中的索引类型
 */
@Document(indexName = "esmodel9")
@Data
public class EsModel extends BaseSJFZEntity {

    /*** 索引id*/
    @Field(type = FieldType.Long)
    private String id;

    /**** es中对应的数据库业务单据id*/
    @Field(analyzer = "ik_max_word")
    private String ctId;

    /**** es中业务数据 对应的业务数据库表名称*/
    @Field(analyzer = "ik_max_word")
    private String ctTableName;

    /**** es中业务数据 对应的 业务简称*/
    @Field(analyzer = "ik_max_word")
    private String ctName;


    /**** es中业务数据 对应的 业务内容详细信息*/
    @Field(analyzer = "ik_max_word")
    private String ctContent;

/*    *//** 创建者 *//*
    //@Field(analyzer = "ik_max_word")
    private String createUser;

    *//** 创建时间 *//*
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    //@Field(analyzer = "ik_max_word")
    private Date createTime;

    *//** 更新者 *//*
   // @Field(analyzer = "ik_max_word")
    private String updateUser;

    *//** 更新时间 *//*
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
   // @Field(analyzer = "ik_max_word")
    private Date updateTime;*/

    /** 备注 */
    @Field(analyzer = "ik_max_word")
    private String remark;

    /** 备用1 */
    @Field(analyzer = "ik_max_word")
    private String by1;

    /** 备用2 */
    @Field(analyzer = "ik_max_word")
    private String by2;

    /** 备用3 */
    @Field(analyzer = "ik_max_word")
    private String by3;

    /** 备用4 */
    @Field(analyzer = "ik_max_word")
    private String by4;

    /** 备用5 */
    @Field(analyzer = "ik_max_word")
    private String by5;

}

2.

package com.admin.controller;
import com.admin.common.annotation.Log;
import com.admin.common.core.controller.BaseController;
import com.admin.common.core.domain.AjaxResult;
import com.admin.common.core.page.TableDataInfo;
import com.admin.common.enums.BusinessType;
import com.admin.model.EsModel;
import com.admin.service.EsService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * es -spi
 *
 * @author wangwei
 * @date 2024-04-25
 */
@Api(tags = "ES-api")
@RestController
@RequestMapping("/es/api")
public class EsController extends BaseController {

    @Autowired
    private EsService esService;

    /***
     *从es中按指定字段值获取数据
     * @param key
     * @return
     */
    @ApiOperation(value = "查询 从es中按指定字段值获取数据")
    @GetMapping("/list")
    public AjaxResult list(String key, Pageable pageable) {
        AjaxResult ajaxResult = esService.searchES(key, pageable);
        return ajaxResult;
    }

    /***
     * 全文检索
     *查询 从es中全文检索所包含的 业务数据信息
     * eg:es中的数据字段有 name, contene,等,接口查询条件key  包含在所有字段中的业务数据信息
     * @param key
     * @return
     */
    @ApiOperation(value = "查询 从es中全文检索所包含的 业务数据信息")
    @GetMapping("/whole")
    public TableDataInfo searchWhole(String key, Pageable pageable) {
        List<EsModel> list = esService.searchWhole(key, pageable);
        return getDataTable(list);
    }

    /****
     * es中数据新增
     */
    @ApiOperation(value = "es中数据新增" )
    @Log(title = "es中数据新增" , businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody EsModel esModel) {
        return toAjax(esService.insertEsModel(esModel));
    }

    /****
     * es中数据修改
     */
    @ApiOperation(value = "es中数据修改" )
    @Log(title = "es中数据修改" , businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult put(@RequestBody EsModel esModel) {
        return toAjax(esService.updateEsModel(esModel));
    }

    /**
     * 删除es中的数据
     */
    @ApiOperation(value = "删除es中的数据")
    @Log(title = "删除es中的数据", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ctId}")
    public AjaxResult remove(@PathVariable String ctId) {
        return toAjax(esService.deleteById(ctId));
    }


}

3.

package com.admin.service.impl;

import com.admin.common.core.domain.AjaxResult;
import com.admin.common.exception.CustomException;
import com.admin.common.utils.StringUtils;
import com.admin.constant.EsConstants;
import com.admin.model.EsModel;
import com.admin.repository.EsModelRepository;
import com.admin.service.EsService;
import com.admin.util.HighlightResultMapper;
import com.alibaba.fastjson.JSON;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import static org.elasticsearch.index.query.QueryBuilders.matchQuery;

@Service
public class EsServiceImpl implements EsService {

    @Autowired
    private EsModelRepository esModelRepository;

    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    @Autowired
    private RestHighLevelClient client;

    @Override
    public AjaxResult searchES(String key, Pageable pageable) {
        Page<EsModel> ctContent = esModelRepository.findEsModelByCtContent(key, pageable);
        return AjaxResult.success(ctContent);
    }

    /***
     * 全文检索
     * @param key
     * @return
     */
    @Override
    public  List<EsModel> searchWhole(String key, Pageable pageable) {
        //高亮字段设置
        String ctName = "ctName";
        String ctContent = "ctContent";
        String remark = "remark";
        String preTags = "<span style=\"color:#F56C6C\">";
        String postTags = "</span>";
        HighlightBuilder.Field ctNameField = new HighlightBuilder.Field(ctName).preTags(preTags).postTags(postTags);
        HighlightBuilder.Field ctContentField = new HighlightBuilder.Field(ctContent).preTags(preTags).postTags(postTags);
        HighlightBuilder.Field remarkField = new HighlightBuilder.Field(remark).preTags(preTags).postTags(postTags);

        if (StringUtils.isEmpty(key)) {
            //throw new CustomException("请输入搜索内容!");
            List<EsModel> contentList = new ArrayList<>();
            return contentList;
        }

        //只要数据中包含就能检索到数据 (类似于模糊查询,有分词器的效果)
        //不同类别检索的进阶示例: https://www.cnblogs.com/jelly12345/p/14765477.html
        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withPageable(pageable)//分页
                .withQuery(QueryBuilders.multiMatchQuery(key, "ctName", "ctContent", "remark"))
                .withHighlightFields(ctNameField, ctContentField, remarkField)//设置高亮
               // .withSort(SortBuilders.fieldSort("date").order(SortOrder.DESC))//排序
                .build();

        Page<EsModel> esModels = null;
        try {
            esModels =  elasticsearchRestTemplate.queryForPage(searchQuery, EsModel.class, new HighlightResultMapper());
        }catch (Exception e){
            throw new CustomException("数据检索失败,请联系管理员处理!");
        }

        List<EsModel> contentList = esModels.getContent();
        return contentList;
    }


    /****
     *数据插入es中
     * @param esModel
     * @return
     */
    @Override
    public int insertEsModel(EsModel esModel) {
        try {
            esModel.setCtId(UUID.randomUUID().toString());
            EsModel save = esModelRepository.save(esModel);
        } catch (Exception e) {
            System.out.println("==================================错误信息是:"+e.getMessage()+"============================");
            throw new CustomException("ES数据新增失败,请联系管理员处理!");
        }
        return 1;
    }

    /***
     *es-update  https://www.jb51.net/article/246798.htm
     * @param esModel
     * @return
     */
    @Override
    public int updateEsModel(EsModel esModel) {
        UpdateRequest updateRequest = new UpdateRequest(EsConstants.ES_INDEX, EsConstants.ES_INDEX_TYPE, String.valueOf(esModel.getCtId()));
        //更新    将对象转换为json
        updateRequest.doc(JSON.toJSONString(esModel), XContentType.JSON);

        //客户端发送请求,进行更新
        UpdateResponse update = null;
        try {
            update = client.update(updateRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new CustomException("ES数据同步失败可能原因是es中的业务ctId在数据库中不存在,请查看es客户端查询验证,请联系管理员处理!");
        }

        if (!"OK".equals(update.status().toString())) {
            throw new CustomException("ES数据修改失败,请联系管理员处理!");
        }
        return 1;

    }

    /***
     * 删除es中的数据
     * @param ctId
     * @return
     */
    @Override
    public int deleteById(String ctId) {
        try {
            esModelRepository.deleteById(ctId);
        }catch (Exception e){
            throw new CustomException("ES数据删除失败,请联系管理员处理!");
        }
        return 1;
    }

}


4.

package com.admin.repository;
import com.admin.model.EsModel;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;

/**
 * @author wangwei
 * @date 2024-04-25 14:12:36
 */
@Repository
public interface EsModelRepository extends ElasticsearchRepository<EsModel, String> {


    /*****
     * 这儿查询的  findBy 根据idea 的补全查询(eg:ByCtContent 将查询es中的 字段名称为 ctContent 中的值)
     * @param ket
     * @param pageable
     * @return
     */
    Page<EsModel> findEsModelByCtContent(String ket, Pageable pageable);

    /****
     * 删除es操作
     */
    public void deleteById(Long id);


}

5.检索结果高亮显示

package com.admin.util;

import com.alibaba.fastjson.JSON;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
import java.lang.reflect.Field;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;


/***
 * 检索高亮设置
 * @author wangwei
 * @date 2024-04-25 11:55
 */
public class HighlightResultMapper implements SearchResultMapper {
    @Override
    public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
        long totalHits = response.getHits().getTotalHits();
        List<T> list = new ArrayList<>();
        SearchHits hits = response.getHits();
        if (hits.getHits().length> 0) {
            for (SearchHit searchHit : hits) {
                Map<String, HighlightField> highlightFields = searchHit.getHighlightFields();
                T item = JSON.parseObject(searchHit.getSourceAsString(), clazz);
                Field[] fields = clazz.getDeclaredFields();
                for (Field field : fields) {
                    field.setAccessible(true);
                    if (highlightFields.containsKey(field.getName())) {
                        try {
                            field.set(item, highlightFields.get(field.getName()).fragments()[0].toString());
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }
                    }
                }
                list.add(item);
            }
        }
        return new AggregatedPageImpl<>(list, pageable, totalHits);
    }

    @Override
    public <T> T mapSearchHit(SearchHit searchHit, Class<T> type) {
        return null;
    }
}

6.vue

<template>
  <div class="app-container">
    <el-row :gutter="20">

      <!--用户数据-->
      <el-col :span="20" :xs="24">
        <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px" style="text-align: center">
          <el-form-item label="检索内容" prop="key" >
            <el-input
              v-model="queryParams.key"
              placeholder="请输入检索内容"
              clearable
              size="small"
              style="width: 240px"
              @keyup.enter.native="handleQuery"
            />
          </el-form-item>
          <el-form-item>
            <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
            <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
          </el-form-item>
        </el-form>


        <el-table  v-loading="loading" :data="tableList" >
          <el-table-column label="编号" align="center" key="ctId" prop="ctId" v-if="columns[0].visible" />
          <el-table-column label="名称" align="center" key="ctName" prop="ctName" v-if="columns[1].visible" :show-overflow-tooltip="true" />
          <el-table-column label="内容" align="center" key="ctContent" prop="ctContent" v-if="columns[2].visible" :show-overflow-tooltip="true" />
          <el-table-column label="备注" align="center" key="remark" prop="remark" v-if="columns[2].visible" :show-overflow-tooltip="true" />
        </el-table>

        <pagination
          v-show="total>0"
          :total="total"
          :page.sync="queryParams.number"
          :limit.sync="queryParams.size"
          @pagination="getList"
        />
      </el-col>
    </el-row>

  </div>
</template>

<script>
  import { list, getWholeList, addEsModel, editEsModel, removeEsModel} from "@/api/search";

import { getToken } from "@/utils/auth";
import { treeselect } from "@/api/system/dept";
import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";

export default {
  name: "User",
  components: { Treeselect },
  data() {
    return {
      // 遮罩层
      loading: true,
      // 选中数组
      ids: [],
      // 非单个禁用
      single: true,
      // 非多个禁用
      multiple: true,
      // 显示搜索条件
      showSearch: true,
      // 总条数
      total: 0,
      // 表格数据
      tableList: [],
      // 弹出层标题
      title: "",
      // 部门树选项
      deptOptions: undefined,
      // 是否显示弹出层
      open: false,
      // 部门名称
      deptName: undefined,
      // 默认密码
      initPassword: undefined,
      // 日期范围
      dateRange: [],
      // 状态数据字典
      statusOptions: [],
      // 性别状态字典
      sexOptions: [],
      // 岗位选项
      postOptions: [],
      // 角色选项
      roleOptions: [],
      // 表单参数
      form: {},
      defaultProps: {
        children: "children",
        label: "label"
      },
      // 查询参数
      queryParams: {
        number: 1,
        size: 10,
      },
      // 列信息
      columns: [
        { key: 0, label: `编号`, visible: true },
        { key: 1, label: `名称`, visible: true },
        { key: 2, label: `内容`, visible: true },
      ],
      // 表单校验
      rules: {

      }
    };
  },
  watch: {

  },
  created() {
    this.getList();
  },
  methods: {
    /** 查询用户列表 */
    getList() {
      this.loading = true;
      console.log(this.queryParams)
      getWholeList(this.queryParams).then(response => {
          this.tableList = response.rows;
          this.total = response.total;
          this.loading = false;
        });
    },

    // 取消按钮
    cancel() {
      this.open = false;
      this.reset();
    },
    // 表单重置
    reset() {
      this.form = {
        ctId: undefined,
        ctName: undefined,
        ctContent: undefined,
        remark: undefined,
      };
      this.resetForm("form");
    },
    /** 搜索按钮操作 */
    handleQuery() {
      //this.queryParams.page = 1;
      this.getList();
    },
    /** 重置按钮操作 */
    resetQuery() {
      this.dateRange = [];
      this.resetForm("queryForm");
      this.handleQuery();
    },
  }
};
</script>

7.

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王大锤4391

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值