Commit 447bda8b authored by 郭武斌's avatar 郭武斌

*)新增elasticsearch,实现相似警情搜索

parent d1569044
......@@ -20,6 +20,11 @@ spring.redis.lettuce.pool.max-idle=10
spring.redis.lettuce.pool.min-idle=0
spring.redis.expire.time=300
#ES
spring.data.elasticsearch.cluster-name=elasticsearch
spring.data.elasticsearch.cluster-nodes=172.16.3.3:9300
spring.elasticsearch.rest.uris=http://172.16.3.3:9200
security.systemctl.name=AMOS-API-SYSTEMCTL
......
package com.yeejoin.amos.boot.module.jcs.api.entity;
import java.util.Date;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.DateFormat;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
/**
*
* <pre>
* 警情信息ES实体
* </pre>
*
* @author gwb
* @version $Id: ESAlertCalled.java, v 0.1 2021年6月19日 下午5:12:31 gwb Exp $
*/
@Data
@Accessors(chain = true)
@Document(indexName = "jcs", type = "alertCalled", shards = 1, replicas = 0)
public class ESAlertCalled {
/** 主键 */
@Id
private Long sequenceNbr;
/**
* 警情状态
*/
@ApiModelProperty(value = " 警情状态")
@Field(type = FieldType.Text, searchAnalyzer = "ik_smart", analyzer = "ik_smart")
private Boolean alertStatus;
// /**
// * 系统/人工
// */
// @Field(type = FieldType.Text, searchAnalyzer = "ik_max_word", analyzer = "ik_max_word")
// private String type;
// @Field(type = FieldType.Text, searchAnalyzer = "ik_max_word", analyzer = "ik_max_word")
// private String alertStage;
// /**
// * 报警类型
// */
// @Field(type = FieldType.Text, searchAnalyzer = "ik_max_word", analyzer = "ik_max_word")
// private String alarmType;
/**
* 响应级别字典code 为了过滤用(只有航空器故障有)
*/
@ApiModelProperty(value = "响应级别")
@Field(type = FieldType.Text)
private String responseLevelCode;
/**
* 警情阶段
*/
@ApiModelProperty(value = "警情阶段")
@Field(type = FieldType.Text)
private String alertStage;
// /**
// * 报警类型code
// */
// @Field(type = FieldType.Text, searchAnalyzer = "ik_max_word", analyzer = "ik_max_word")
// private String alarmTypeCode;
// /**
// * 通话记录信息id
// */
// @Field(type = FieldType.Text, searchAnalyzer = "ik_max_word", analyzer = "ik_max_word")
// private Integer callRecordId;
// /**
// * 父警情id
// */
// private Long fatherAlert;
/**
* 联系人姓名
*/
@ApiModelProperty(value = "联系人姓名")
@Field(type = FieldType.Text)
private String contactUser;
/**
* 联系人电话
*/
@ApiModelProperty(value = "联系人电话")
@Field(type = FieldType.Text)
private String contactPhone;
/**
* 接警时间
*/
@ApiModelProperty(value = "接警时间")
@Field(type = FieldType.Date, format = DateFormat.basic_date_time)
private Date callTime;
// /**
// * 接警时长
// */
// private Double callTimeNum;
// /**
// * 警情来源
// */
// private String alertSource;
// /**
// * 警情来源code
// */
// private String alertSourceCode;
/**
* 警情类型
*/
@ApiModelProperty(value = "警情类型")
@Field(type = FieldType.Text, searchAnalyzer = "ik_smart", analyzer = "ik_smart")
private String alertType;
// /**
// * 警情类型code
// */
// private String alertTypeCode;
/**
* 事发单位
*/
@ApiModelProperty(value = "事发单位")
@Field(type = FieldType.Text, searchAnalyzer = "ik_max_word", analyzer = "ik_max_word")
private String unitInvolved;
// /**
// * 被困人数
// */
// private Integer trappedNum;
// /**
// * 伤亡人数
// */
// private Integer casualtiesNum;
/**
* 地址
*/
@ApiModelProperty(value = "地址")
@Field(type = FieldType.Text, searchAnalyzer = "ik_max_word", analyzer = "ik_max_word")
private String address;
// /**
// * 救援方格
// */
// private String rescueGrid;
/**
* 坐标x
*/
@ApiModelProperty(value = "坐标x")
private String coordinateX;
/**
* 坐标y
*/
@ApiModelProperty(value = "坐标y")
private String coordinateY;
// /**
// * 更新时间
// */
// private Date updateTime;
// /**
// * 发送人名称
// */
// private String recUserName;
// /**
// * 接警时间开始---用于列表过滤
// */
// private Date callTimeStart ;
// /**
// * 接警时间结束---用于列表过滤
// */
// private Date callTimeEnd ;
// /**
// * 是否处警
// */
// private Boolean isFatherAlert;
}
......@@ -2,17 +2,19 @@ package com.yeejoin.amos.boot.module.jcs.biz.controller;
import com.yeejoin.amos.boot.biz.common.utils.CommonResponseUtil;
import com.yeejoin.amos.boot.module.jcs.api.entity.AlertFormValue;
import com.yeejoin.amos.boot.module.jcs.api.entity.ESAlertCalled;
import com.yeejoin.amos.boot.module.jcs.api.service.IAlertFormValueService;
import com.yeejoin.amos.boot.module.jcs.api.vo.AlertCalledFormVo;
import com.yeejoin.amos.boot.module.jcs.api.vo.AlertCalledVo;
import com.yeejoin.amos.boot.module.jcs.api.vo.FormValue;
import com.yeejoin.amos.boot.module.jcs.biz.service.impl.ESAlertCalledService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.Api;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.RestController;
import com.yeejoin.amos.boot.biz.common.controller.BaseController;
import com.yeejoin.amos.boot.module.jcs.api.service.IAlertCalledService;
......@@ -27,7 +29,6 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springframework.web.bind.annotation.*;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yeejoin.amos.boot.module.jcs.api.entity.AlertCalled;
import com.yeejoin.amos.boot.module.jcs.api.entity.AlertForm;
import com.yeejoin.amos.boot.biz.common.utils.NameUtils;
import com.yeejoin.amos.boot.biz.common.utils.RedisKey;
import com.yeejoin.amos.boot.biz.common.utils.RedisUtils;
......@@ -35,6 +36,7 @@ import com.yeejoin.amos.boot.biz.common.utils.RedisUtils;
import org.typroject.tyboot.core.foundation.utils.ValidationUtil;
import org.typroject.tyboot.core.restful.doc.TycloudOperation;
import org.typroject.tyboot.core.foundation.enumeration.UserType;
import org.typroject.tyboot.core.restful.utils.ResponseHelper;
import org.typroject.tyboot.core.restful.utils.ResponseModel;
import java.lang.reflect.Field;
......@@ -60,6 +62,8 @@ public class AlertCalledController extends BaseController {
@Autowired
IAlertFormValueService iAlertFormValueService;
@Autowired
private ESAlertCalledService eSAlertCalledService;
@Autowired
RedisUtils redisUtils;
@Value("${redis.cache.failure.time}")
private long time;
......@@ -179,6 +183,28 @@ public class AlertCalledController extends BaseController {
}
/**
*
* <pre>
* 相似警情分页查询
* </pre>
*
* @param alertCalled
* @param current
* @param size
* @return
* @throws Exception
*/
@TycloudOperation(ApiLevel = UserType.AGENCY)
@ApiOperation(value = "相似警情分页查询")
@RequestMapping(value = "/page/similar", method = RequestMethod.POST)
public ResponseModel<Page<ESAlertCalled>> pageBySimilar(
@RequestBody ESAlertCalled alertCalled,
@RequestParam(value = "current") int current,
@RequestParam(value = "size") int size) throws Exception {
return ResponseHelper.buildResponse(eSAlertCalledService.queryByKeys(alertCalled, current, size));
}
/**
* 列表无分页查询
*
* @return
......
package com.yeejoin.amos.boot.module.jcs.biz.dao;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
import com.yeejoin.amos.boot.module.jcs.api.entity.ESAlertCalled;
/**
*
* <pre>
* 警情信息ES数据查询
* </pre>
*
* @author gwb
* @version $Id: ESAlertCalledRepository.java, v 0.1 2021年6月19日 下午5:12:50 gwb Exp $
*/
@Repository
public interface ESAlertCalledRepository extends PagingAndSortingRepository<ESAlertCalled, Long> {
}
package com.yeejoin.amos.boot.module.jcs.biz.service.impl;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.annotation.PostConstruct;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.typroject.tyboot.core.foundation.utils.ValidationUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yeejoin.amos.boot.module.jcs.api.entity.AlertCalled;
import com.yeejoin.amos.boot.module.jcs.api.entity.ESAlertCalled;
import com.yeejoin.amos.boot.module.jcs.api.service.IAlertCalledService;
import com.yeejoin.amos.boot.module.jcs.biz.dao.ESAlertCalledRepository;
/**
*
* <pre>
* 警情信息ES检索服务
* </pre>
*
* @author gwb
* @version $Id: ESAlertCalledService.java, v 0.1 2021年6月19日 下午5:12:01 gwb Exp $
*/
@Service
public class ESAlertCalledService {
@Autowired
private ElasticsearchRestTemplate elasticsearchTemplate;
@Autowired
private ESAlertCalledRepository esAlertCalledRepository;
@Autowired
private IAlertCalledService iAlertCalledService;
@PostConstruct
public void init()
{
//初始化ES,重建索引
initEs();
}
/**
*
* <pre>
* 批量保存
* </pre>
*
* @param list 警情信息列表
*/
public void saveAll(List<ESAlertCalled> list) {
esAlertCalledRepository.saveAll(list);
}
/**
* 查询所有,根据接警时间降序排列
*
* @param current 页码
* @param size 页面大小
* @return Page对象
*/
// public Page<ESAlertCalled> findAll(int current, int size) {
// // 分页+排序
// Sort.Order order=new Sort.Order(Sort.Direction.DESC, "callTime");
// return esAlertCalledRepository.findAll(PageRequest.of(current, size, Sort.by(order)));
// }
/**
* 根据id查询ES存储对象
*
* @param sequenceNbr id
* @return ES实例
*/
public ESAlertCalled queryById(Long sequenceNbr) {
return esAlertCalledRepository.findById(sequenceNbr).orElse(null);
}
/**
* 根据关键字查询文档,关键字不为空时按相关性从大到小排序
*
* @param queryStr 关键字
* @param current 当前页码
* @param size 页面大小
* @return
*/
@SuppressWarnings({ "rawtypes" })
public Page<ESAlertCalled> queryByKeys(ESAlertCalled alertCalled, int current, int size)
{
// 条件构造,多条件循环匹配
BoolQueryBuilder boolMust = QueryBuilders.boolQuery();
long currentTime = System.currentTimeMillis() ;
currentTime = currentTime - 30*60*1000;
Date date=new Date(currentTime);
boolMust.must(
QueryBuilders.boolQuery().minimumShouldMatch(1)
.should(QueryBuilders.termQuery("contactUser", alertCalled.getContactUser()))//联系人姓名
.should(QueryBuilders.termQuery("contactPhone", alertCalled.getContactPhone()))//联系人电话
.should(QueryBuilders.rangeQuery("callTime").gte(date))//接警时间,距离当前时间不超过半小时的
.should(QueryBuilders.termQuery("alertType", alertCalled.getAlertType()))//警情类型
.should(QueryBuilders.matchQuery("address", alertCalled.getAddress()))//事发地址
.should(QueryBuilders.matchQuery("unitInvolved", alertCalled.getUnitInvolved())) //事发单位
);
// 创建查询构造器
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder()
// 分页
.withPageable(PageRequest.of(current, size))
// 排序
// .withSort(SortBuilders.fieldSort("callTime").order(SortOrder.DESC))
//过滤条件
.withQuery(boolMust);
// List<ESAlertCalled> articleEntities = elasticsearchTemplate.queryForObject(queryBuilder, ESAlertCalled.class);
// 对高亮词条进行操作
SearchHits<ESAlertCalled> searchHits =elasticsearchTemplate.search(queryBuilder.build(), ESAlertCalled.class);
Page<ESAlertCalled> result = new Page<ESAlertCalled>(current, size);
List<ESAlertCalled> list = new ArrayList<>();
for (SearchHit searchHit : searchHits.getSearchHits())
{
JSONObject jsonObject = (JSONObject) JSONObject.toJSON(searchHit.getContent());
ESAlertCalled eSAlertCalled =JSONObject.toJavaObject(jsonObject, ESAlertCalled.class);
list.add(eSAlertCalled);
}
result.setRecords(list);
result.setTotal(searchHits.getTotalHits());
// Page<ESAlertCalled> result = new PageImpl(searchHits.getSearchHits(),
// PageRequest.of(current, size), searchHits.getTotalHits());
// SearchHits<ESAlertCalled> result = elasticsearchTemplate.search(queryBuilder, ESAlertCalled.class, new SearchHitMapping() {
//// public <T> SearchHits<T> mapResults(SearchResponse response, Class<T> aClass, Pageable pageable) {
//// List<ESAlertCalled> list = new ArrayList<>();
////// for (SearchHit searchHit : response.getHits()) {
////// ESAlertCalled docEntity = JSON.parseObject(searchHit.getSourceAsString(), ESAlertCalled.class);
////// // 文档标题
////// HighlightField docTitle = searchHit.getHighlightFields().get("docTitle");
////// if (docTitle != null) {
////// docEntity.setDocTitle(docTitle.fragments()[0].toString());
////// }
////// // 文档内容
////// HighlightField textContent = searchHit.getHighlightFields().get("textContent");
////// if (textContent != null) {
////// docEntity.setSummary(textContent.fragments()[0].toString());
////// }
////// Set<String> tagInfoSet = new HashSet<>();
////// // 文档标签
////// HighlightField docTagsInfo = searchHit.getHighlightFields().get("docTags.tagInfo");
////// if (docTagsInfo != null) {
////// for (Text name : docTagsInfo.getFragments()) {
////// tagInfoSet.add(name.toString());
////// }
////// }
////// HighlightField contentTagsInfo = searchHit.getHighlightFields().get("contentTags.tagInfo");
////// if (contentTagsInfo != null) {
////// for (Text name : contentTagsInfo.getFragments()) {
////// tagInfoSet.add(name.toString());
////// }
////// }
////// // 删除不匹配的和重复的标签
////// deleteRepeatedTags(docEntity.getDocTags(), tagInfoSet);
////// deleteRepeatedTags(docEntity.getContentTags(), tagInfoSet);
//////
////// list.add(docEntity);
////// }
//// return new SearchHitsImpl<T>((List<T>) list, PageRequest.of(current, size), response.getHits().getTotalHits());
//// }
// });
return result;
}
//
// /**
// * 为搜索结果添加人名翻译/汇总信息
// *
// * @param key 查询关键字
// * @param current 页码
// * @param size 每页数量
// * @return Page对象
// */
// public com.baomidou.mybatisplus.extension.plugins.pagination.Page queryAndDetail(String key, int current, int size) {
// List<Map<String, Object>> resList = new ArrayList<>();
// Page<ESAlertCalled> entityPage = queryByKeys(key, current, size);
// List<ESAlertCalled> docEntityList = entityPage.getContent();
// Set<String> userSet = new HashSet<>();
// for (ESAlertCalled ESAlertCalled : docEntityList) {
// KnowledgeDocContentModel contentModel = JSON.parseObject(ESAlertCalled.getDocJson(), KnowledgeDocContentModel.class);
// List<KnowledgeDynamicsValueModel> listByInstance = dynamicsValueService.queryByInstanceId(contentModel.getSequenceNbr());
// Map<String, Object> fieldMap = Bean.listToMap(listByInstance, "fieldName", "fieldValue", KnowledgeDynamicsValueModel.class);
// Map<String, Object> map = Bean.BeantoMap(ESAlertCalled);
// // 收藏数/引用数
// map.put("referenceNum", docLibraryService.getReferenceCount(contentModel.getSequenceNbr()));
// map.put("collectionNum", docLibraryService.getCollectionCount(contentModel.getSequenceNbr()));
// map.put("userId", contentModel.getUserId());
// userSet.add(contentModel.getUserId());
// map.putAll(fieldMap);
// resList.add(map);
// }
// Map<String, String> userMap = RemoteData.getUserMap(userSet);
// for (Map<String, Object> map : resList) {
// map.put("userName", userMap.get(map.get("userId")));
// map.remove("htmlContent");
// map.remove("docJson");
// }
// com.baomidou.mybatisplus.extension.plugins.pagination.Page page = new com.baomidou.mybatisplus.extension.plugins.pagination.Page();
// page.setTotal(entityPage.getTotalElements());
// page.setSize(size);
// page.setRecords(resList);
// return page;
// }
/**
*
* <pre>
* 根据警情记录批量保存
* </pre>
*
* @param alertCalleds 警情信息列表
*/
public Boolean saveAlertCalledToES(List<AlertCalled> alertCalleds)
{
if (!ValidationUtil.isEmpty(alertCalleds))
{
List<ESAlertCalled> esAlertCalleds = new ArrayList<>();
for (AlertCalled alertCalled : alertCalleds)
{
ESAlertCalled esAlertCalled = new ESAlertCalled();
esAlertCalled.setSequenceNbr(alertCalled.getSequenceNbr());
esAlertCalled.setAlertType(alertCalled.getAlarmType());
esAlertCalled.setCallTime(alertCalled.getCallTime());
esAlertCalled.setContactUser(alertCalled.getContactUser());
esAlertCalled.setContactPhone(alertCalled.getContactPhone());
esAlertCalled.setUnitInvolved(alertCalled.getUnitInvolved());
esAlertCalled.setCoordinateX(alertCalled.getCoordinateX());
esAlertCalled.setCoordinateY(alertCalled.getCoordinateY());
esAlertCalleds.add(esAlertCalled);
}
this.saveAll(esAlertCalleds);
}
return true;
}
// /**
// * 将文档基本信息转为关键字符串
// *
// * @param baseInfo 基本信息
// * @param enumCnEnMap 枚举字典数据
// * @return
// */
// private String baseInfo2Str(Map<String, Object> baseInfo, Map<String, Map<String, String>> enumCnEnMap) {
// StringBuilder infoStr = new StringBuilder();
// for (String field : baseInfo.keySet()) {
// if (DocContentService.DOC_TITLE.equals(field)) {
// continue;
// }
// if (enumCnEnMap.containsKey(field)) {
// String enumCn = enumCnEnMap.get(field).get(baseInfo.get(field));
// if (!ValidationUtil.isEmpty(enumCn)) {
// infoStr.append(enumCn).append(" ");
// }
// } else {
// Object value = baseInfo.get(field);
// if (!ValidationUtil.isEmpty(value)) {
// infoStr.append(value.toString()).append(" ");
// }
// }
// }
// return infoStr.toString().trim();
// }
// /**
// * 根据标签实例列表创建ES标签列表
// */
// private List<ESTagEntity> buildESTagsByInstanceList(List<KnowledgeTagInstanceModel> instanceList) {
// List<ESTagEntity> tags = new ArrayList<>();
// if (!ValidationUtil.isEmpty(instanceList)) {
// for (KnowledgeTagInstanceModel instanceModel : instanceList) {
// ESTagEntity tag = new ESTagEntity()
// .setSequenceNbr(instanceModel.getSequenceNbr())
// .setTagSeq(instanceModel.getTagSeq())
// .setTagName(instanceModel.getTagName())
// .setTagInfo(getTagInfoStr(instanceModel))
// .setTagJson(JSON.toJSONString(instanceModel));
// tags.add(tag);
// }
// }
// return tags;
// }
//
// /**
// * 获取标签信息:标签名&值
// *
// * @param instanceModel 标签实例
// * @return 信息文本
// */
// private String getTagInfoStr(KnowledgeTagInstanceModel instanceModel) {
// StringBuilder infoStr = new StringBuilder();
// infoStr.append(instanceModel.getTagName()).append(" ");
// if (TagService.TAG_TYPE_TEXT.equals(instanceModel.getTagType())
// || ValidationUtil.isEmpty(instanceModel.getTagValues())) {
// return infoStr.toString().trim();
// }
// for (KnowledgeTagValueModel valueModel : instanceModel.getTagValues()) {
// String fieldName = valueModel.getFieldName();
// String tagValue = valueModel.getTagValue();
// switch (fieldName) {
// case TagValueService.VALUE_TAG_FIELD_DATE_H:
// infoStr.append(tagValue).append(" ");
// try {
// Date date = DateUtil.formatStringToDate(tagValue, null);
// infoStr.append(DateUtil.formatDate(date, DateUtil.YMD)).append(" ");
// infoStr.append(DateUtil.formatDate(date, DateUtil.YMDHM)).append(" ");
// infoStr.append(DateUtil.formatDate(date, DateUtil.ymd)).append(" ");
// infoStr.append(DateUtil.formatDate(date, DateUtil.Y_M_D)).append(" ");
// infoStr.append(DateUtil.formatDate(date, COMMON_FORMAT)).append(" ");
// } catch (Exception e) {
// e.printStackTrace();
// }
// break;
// default:
// infoStr.append(tagValue).append(" ");
// }
// }
// return infoStr.toString().trim();
// }
/**
*
* <pre>
* 从ES库批量删除
* </pre>
*
* @param ids
* @return
* @throws Exception
*/
public Boolean deleteById(List<Long> ids) throws Exception{
if (!ValidationUtil.isEmpty(ids)) {
for (Long sequenceNbr : ids) {
if (esAlertCalledRepository.existsById(sequenceNbr)) {
esAlertCalledRepository.deleteById(sequenceNbr);
}
}
}
return true;
}
/**
* 重建索引
*/
public Boolean initEs() {
esAlertCalledRepository.deleteAll();
/**
* 同步历史48小时以内的警情处置记录
*/
QueryWrapper<AlertCalled> wrapper = new QueryWrapper<>();
long currentTime = System.currentTimeMillis() ;
currentTime = currentTime - 480*60*60*1000;
Date date=new Date(currentTime);
wrapper.ge("call_time", date);
List<AlertCalled> alertCalleds = iAlertCalledService.list(wrapper);
if (!ValidationUtil.isEmpty(alertCalleds))
{
saveAlertCalledToES(alertCalleds);
}
return true;
}
}
......@@ -13,6 +13,11 @@
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
</dependencies>
<modules>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment