1.添加对es精准查询,去除去条件操作
2.添加搜索时对条件就行拆分操作
This commit is contained in:
@@ -3,6 +3,7 @@ package com.ruoyi.cms.controller.app;
|
|||||||
import com.ruoyi.cms.domain.ESJobDocument;
|
import com.ruoyi.cms.domain.ESJobDocument;
|
||||||
import com.ruoyi.cms.domain.Job;
|
import com.ruoyi.cms.domain.Job;
|
||||||
import com.ruoyi.cms.domain.JobApply;
|
import com.ruoyi.cms.domain.JobApply;
|
||||||
|
import com.ruoyi.cms.domain.ik.JobSearchCondition;
|
||||||
import com.ruoyi.cms.domain.query.ESJobSearch;
|
import com.ruoyi.cms.domain.query.ESJobSearch;
|
||||||
import com.ruoyi.cms.service.*;
|
import com.ruoyi.cms.service.*;
|
||||||
import com.ruoyi.cms.util.RoleUtils;
|
import com.ruoyi.cms.util.RoleUtils;
|
||||||
@@ -17,6 +18,7 @@ import com.ruoyi.common.utils.DateUtils;
|
|||||||
import com.ruoyi.common.utils.SM4Utils;
|
import com.ruoyi.common.utils.SM4Utils;
|
||||||
import com.ruoyi.common.utils.SiteSecurityUtils;
|
import com.ruoyi.common.utils.SiteSecurityUtils;
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
|
import com.ruoyi.common.utils.bean.BeanUtils;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
import io.swagger.annotations.ApiParam;
|
import io.swagger.annotations.ApiParam;
|
||||||
@@ -50,6 +52,8 @@ public class AppJobController extends BaseController
|
|||||||
private SensitiveWordChecker sensitiveWordChecker;
|
private SensitiveWordChecker sensitiveWordChecker;
|
||||||
@Autowired
|
@Autowired
|
||||||
private IJobApplyService jobApplyService;
|
private IJobApplyService jobApplyService;
|
||||||
|
@Autowired
|
||||||
|
private JobNaturalSearchService jobNaturalSearchService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询岗位列表
|
* 查询岗位列表
|
||||||
@@ -58,6 +62,10 @@ public class AppJobController extends BaseController
|
|||||||
@GetMapping("/list")
|
@GetMapping("/list")
|
||||||
public TableDataInfo list(ESJobSearch job)
|
public TableDataInfo list(ESJobSearch job)
|
||||||
{
|
{
|
||||||
|
if(!StringUtils.isBlank(job.getJobTitle())){
|
||||||
|
JobSearchCondition parserDictDTO=jobNaturalSearchService.parseNaturalText(job.getJobTitle());
|
||||||
|
BeanUtils.copyBeanProp(job, parserDictDTO);
|
||||||
|
}
|
||||||
EsPageInfo<ESJobDocument> list = jobService.appList(job);
|
EsPageInfo<ESJobDocument> list = jobService.appList(job);
|
||||||
return getTableDataInfo2(list,job);
|
return getTableDataInfo2(list,job);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package com.ruoyi.cms.controller.cms;
|
||||||
|
|
||||||
|
import com.ruoyi.cms.domain.ik.JobSearchCondition;
|
||||||
|
import com.ruoyi.cms.service.JobNaturalSearchService;
|
||||||
|
import com.ruoyi.common.annotation.Anonymous;
|
||||||
|
import org.elasticsearch.index.query.BoolQueryBuilder;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
public class JobSearchController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private JobNaturalSearchService jobNaturalSearchService;
|
||||||
|
|
||||||
|
@PreAuthorize("@ss.hasPermi('job:naturalSearch')")
|
||||||
|
@GetMapping("/job/naturalSearch")
|
||||||
|
// @Anonymous
|
||||||
|
public Object naturalSearch(@RequestParam String keyword) {
|
||||||
|
// 1、解析自然语句
|
||||||
|
JobSearchCondition condition = jobNaturalSearchService.parseNaturalText(keyword);
|
||||||
|
// 2、组装ES查询条件
|
||||||
|
BoolQueryBuilder boolQuery = jobNaturalSearchService.buildEsQuery(condition);
|
||||||
|
|
||||||
|
System.out.println("解析后的条件:" + condition);
|
||||||
|
System.out.println("构建的ES查询DSL:" + boolQuery);
|
||||||
|
|
||||||
|
// TODO 此处执行ES搜索,传入boolQuery 查询职位数据
|
||||||
|
return condition;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.ruoyi.cms.domain.ik;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class JobSearchCondition {
|
||||||
|
/** 岗位名称 */
|
||||||
|
private String jobTitle;
|
||||||
|
/** 工作地点文本(原始区县名称) */
|
||||||
|
private String address;
|
||||||
|
/** 区划编码(业务编码) */
|
||||||
|
private String jobLocationAreaCode;
|
||||||
|
|
||||||
|
/** 最低年限(数字区间range) */
|
||||||
|
private Integer workYearMin;
|
||||||
|
/** 最高年限(数字区间range) */
|
||||||
|
private Integer workYearMax;
|
||||||
|
/** 工作经验字典编码 0~7 */
|
||||||
|
private String experience;
|
||||||
|
|
||||||
|
/** 最低薪资(元) */
|
||||||
|
private Long minSalary;
|
||||||
|
/** 最高薪资(元) */
|
||||||
|
private Long maxSalary;
|
||||||
|
|
||||||
|
/** 学历编码 -1 ~ 6 */
|
||||||
|
private String education;
|
||||||
|
/** 匹配到的学历原始文本(本科/大专...用于过滤岗位名称) */
|
||||||
|
private String educationText;
|
||||||
|
/** 匹配到的工作经验原始文本(3-5年/应届毕业生...用于过滤岗位名称) */
|
||||||
|
private String workExpText;
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package com.ruoyi.cms.domain.ik;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class ParserDictDTO {
|
||||||
|
/** 区县名称->编码 */
|
||||||
|
private Map<String, Integer> areaMap;
|
||||||
|
/** 工作经验文本->编码 */
|
||||||
|
private Map<String, Integer> workExpMap;
|
||||||
|
/** 学历文本->编码 */
|
||||||
|
private Map<String, Integer> educationMap;
|
||||||
|
//岗位列表
|
||||||
|
private Set<String> standardJobSet;
|
||||||
|
|
||||||
|
private Map<String,String> jobIndexMap;
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.ruoyi.cms.service;
|
package com.ruoyi.cms.service;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import com.ruoyi.common.core.domain.TreeSelect;
|
import com.ruoyi.common.core.domain.TreeSelect;
|
||||||
import com.ruoyi.common.core.domain.entity.JobTitle;
|
import com.ruoyi.common.core.domain.entity.JobTitle;
|
||||||
@@ -62,4 +63,6 @@ public interface IJobTitleService
|
|||||||
void importJobTitle();
|
void importJobTitle();
|
||||||
|
|
||||||
List<JobTitle> levelOne();
|
List<JobTitle> levelOne();
|
||||||
|
|
||||||
|
Set<String> jobTitleNameSets();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,116 @@
|
|||||||
|
package com.ruoyi.cms.service;
|
||||||
|
|
||||||
|
import com.ruoyi.cms.domain.BussinessDictData;
|
||||||
|
import com.ruoyi.cms.domain.ik.JobSearchCondition;
|
||||||
|
import com.ruoyi.cms.domain.ik.ParserDictDTO;
|
||||||
|
import com.ruoyi.cms.util.DictUtils;
|
||||||
|
import com.ruoyi.cms.util.ik.EsAnalyzeUtil;
|
||||||
|
import com.ruoyi.cms.util.ik.TextConditionParserUtil;
|
||||||
|
import org.elasticsearch.index.query.BoolQueryBuilder;
|
||||||
|
import org.elasticsearch.index.query.QueryBuilders;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class JobNaturalSearchService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private EsAnalyzeUtil esAnalyzeUtil;
|
||||||
|
@Autowired
|
||||||
|
private IJobTitleService jobTitleService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自然语言解析入口
|
||||||
|
*/
|
||||||
|
public JobSearchCondition parseNaturalText(String inputText) {
|
||||||
|
// 1、ES分词
|
||||||
|
List<EsAnalyzeUtil.TokenItem> tokenList = esAnalyzeUtil.analyze(inputText, "ik_max_word");
|
||||||
|
|
||||||
|
// 2、【从Redis加载三份词典】
|
||||||
|
List<BussinessDictData> areaDictList = DictUtils.getDictCache("area");
|
||||||
|
List<BussinessDictData> expDictList = DictUtils.getDictCache("experience");
|
||||||
|
List<BussinessDictData> eduDictList = DictUtils.getDictCache("education");
|
||||||
|
Set<String> standardJobSet = jobTitleService.jobTitleNameSets();
|
||||||
|
Map<String,String> jobIndexMap = new HashMap<>(standardJobSet.size());
|
||||||
|
for(String name : standardJobSet){
|
||||||
|
jobIndexMap.put(name,name);
|
||||||
|
}
|
||||||
|
|
||||||
|
ParserDictDTO dictDTO = new ParserDictDTO();
|
||||||
|
dictDTO.setAreaMap(convertDictListToMap(areaDictList));
|
||||||
|
dictDTO.setWorkExpMap(convertDictListToMap(expDictList));
|
||||||
|
dictDTO.setEducationMap(convertDictListToMap(eduDictList));
|
||||||
|
dictDTO.setStandardJobSet(standardJobSet);
|
||||||
|
dictDTO.setJobIndexMap(jobIndexMap);
|
||||||
|
|
||||||
|
// 3、传入词典执行解析
|
||||||
|
return TextConditionParserUtil.parse(inputText, tokenList, dictDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建ES查询BoolQuery
|
||||||
|
*/
|
||||||
|
public BoolQueryBuilder buildEsQuery(JobSearchCondition condition) {
|
||||||
|
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
|
||||||
|
|
||||||
|
if (condition.getJobTitle() != null && condition.getJobTitle().trim().isEmpty()) {
|
||||||
|
boolQuery.must(QueryBuilders.matchQuery("jobName", condition.getJobTitle()));
|
||||||
|
}
|
||||||
|
if (condition.getJobLocationAreaCode() != null) {
|
||||||
|
boolQuery.filter(QueryBuilders.termQuery("areaCode", condition.getJobLocationAreaCode()));
|
||||||
|
}
|
||||||
|
if (condition.getExperience() != null) {
|
||||||
|
boolQuery.filter(QueryBuilders.termQuery("workExpCode", condition.getExperience()));
|
||||||
|
}
|
||||||
|
if (condition.getEducation() != null) {
|
||||||
|
boolQuery.filter(QueryBuilders.termQuery("educationCode", condition.getEducation()));
|
||||||
|
}
|
||||||
|
if (condition.getWorkYearMin() != null) {
|
||||||
|
boolQuery.filter(QueryBuilders.rangeQuery("workYear").gte(condition.getWorkYearMin()));
|
||||||
|
}
|
||||||
|
if (condition.getWorkYearMax() != null) {
|
||||||
|
boolQuery.filter(QueryBuilders.rangeQuery("workYear").lte(condition.getWorkYearMax()));
|
||||||
|
}
|
||||||
|
if (condition.getMinSalary() != null) {
|
||||||
|
boolQuery.filter(QueryBuilders.rangeQuery("salaryMin").gte(condition.getMinSalary()));
|
||||||
|
}
|
||||||
|
if (condition.getMaxSalary() != null) {
|
||||||
|
boolQuery.filter(QueryBuilders.rangeQuery("salaryMax").lte(condition.getMaxSalary()));
|
||||||
|
}
|
||||||
|
return boolQuery;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字典转换
|
||||||
|
* @param dictDataList
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private Map<String, Integer> convertDictListToMap(List<BussinessDictData> dictDataList) {
|
||||||
|
if (dictDataList == null || dictDataList.isEmpty()) {
|
||||||
|
return new HashMap<>();
|
||||||
|
}
|
||||||
|
return dictDataList.stream()
|
||||||
|
.filter(item -> item.getDictLabel() != null && item.getDictValue() != null)
|
||||||
|
.collect(Collectors.toMap(
|
||||||
|
BussinessDictData::getDictLabel,
|
||||||
|
item -> {
|
||||||
|
try {
|
||||||
|
return Integer.parseInt(item.getDictValue());
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(oldVal, newVal) -> oldVal
|
||||||
|
))
|
||||||
|
.entrySet().stream()
|
||||||
|
.filter(entry -> entry.getValue() != null)
|
||||||
|
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -264,50 +264,50 @@ public class ESJobSearchImpl implements IESJobSearchService
|
|||||||
|
|
||||||
List<ESJobDocument> esJobDocuments = esJobDocumentMapper.selectList(wrapper);
|
List<ESJobDocument> esJobDocuments = esJobDocumentMapper.selectList(wrapper);
|
||||||
|
|
||||||
if (!isCompanyUser &&esJobDocuments.size() < esJobSearch.getPageSize()) {
|
// if (!isCompanyUser &&esJobDocuments.size() < esJobSearch.getPageSize()) {
|
||||||
// 定义要逐步放宽的搜索条件字段
|
// // 定义要逐步放宽的搜索条件字段
|
||||||
List<Runnable> relaxConditions = new ArrayList<>();
|
// List<Runnable> relaxConditions = new ArrayList<>();
|
||||||
relaxConditions.add(() -> newSearch.setArea(null));
|
// relaxConditions.add(() -> newSearch.setArea(null));
|
||||||
relaxConditions.add(() -> newSearch.setExperience(null));
|
// relaxConditions.add(() -> newSearch.setExperience(null));
|
||||||
relaxConditions.add(() -> newSearch.setMaxSalary(null));
|
// relaxConditions.add(() -> newSearch.setMaxSalary(null));
|
||||||
relaxConditions.add(() -> newSearch.setMinSalary(null));
|
// relaxConditions.add(() -> newSearch.setMinSalary(null));
|
||||||
relaxConditions.add(() -> newSearch.setEducation(null));
|
// relaxConditions.add(() -> newSearch.setEducation(null));
|
||||||
relaxConditions.add(()-> newSearch.setJobTitle(null));
|
// relaxConditions.add(()-> newSearch.setJobTitle(null));
|
||||||
// 保存所有查询到的文档
|
// // 保存所有查询到的文档
|
||||||
List<ESJobDocument> allDocuments = new ArrayList<>(esJobDocuments);
|
// List<ESJobDocument> allDocuments = new ArrayList<>(esJobDocuments);
|
||||||
|
//
|
||||||
// 记录已经放宽的条件数量
|
// // 记录已经放宽的条件数量
|
||||||
int relaxedConditions = 0;
|
// int relaxedConditions = 0;
|
||||||
|
//
|
||||||
// 继续放宽条件直到满足分页或所有条件都已放宽
|
// // 继续放宽条件直到满足分页或所有条件都已放宽
|
||||||
while (allDocuments.size() < esJobSearch.getPageSize()
|
// while (allDocuments.size() < esJobSearch.getPageSize()
|
||||||
&& relaxedConditions < relaxConditions.size()) {
|
// && relaxedConditions < relaxConditions.size()) {
|
||||||
// 放宽下一个条件
|
// // 放宽下一个条件
|
||||||
relaxConditions.get(relaxedConditions).run();
|
// relaxConditions.get(relaxedConditions).run();
|
||||||
relaxedConditions++;
|
// relaxedConditions++;
|
||||||
|
//
|
||||||
// 查询新增的文档(不包含之前已经查询到的)
|
// // 查询新增的文档(不包含之前已经查询到的)
|
||||||
wrapper = getWrapper(newSearch, jobIds);
|
// wrapper = getWrapper(newSearch, jobIds);
|
||||||
wrapper.limit(esJobSearch.getPageSize() - allDocuments.size());
|
// wrapper.limit(esJobSearch.getPageSize() - allDocuments.size());
|
||||||
if (!allDocuments.isEmpty()) {
|
// if (!allDocuments.isEmpty()) {
|
||||||
// 排除已经查询到的文档ID
|
// // 排除已经查询到的文档ID
|
||||||
Set<String> existingIds = allDocuments.stream()
|
// Set<String> existingIds = allDocuments.stream()
|
||||||
.map(ESJobDocument::getId)
|
// .map(ESJobDocument::getId)
|
||||||
.collect(Collectors.toSet());
|
// .collect(Collectors.toSet());
|
||||||
wrapper.not().in(ESJobDocument::getId, existingIds);
|
// wrapper.not().in(ESJobDocument::getId, existingIds);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
List<ESJobDocument> newDocuments = esJobDocumentMapper.selectList(wrapper);
|
// List<ESJobDocument> newDocuments = esJobDocumentMapper.selectList(wrapper);
|
||||||
allDocuments.addAll(newDocuments);
|
// allDocuments.addAll(newDocuments);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// 如果总数超过分页大小,截取所需数量
|
// // 如果总数超过分页大小,截取所需数量
|
||||||
if (allDocuments.size() > esJobSearch.getPageSize()) {
|
// if (allDocuments.size() > esJobSearch.getPageSize()) {
|
||||||
esJobDocuments = allDocuments.subList(0, esJobSearch.getPageSize());
|
// esJobDocuments = allDocuments.subList(0, esJobSearch.getPageSize());
|
||||||
} else {
|
// } else {
|
||||||
esJobDocuments = allDocuments;
|
// esJobDocuments = allDocuments;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
return esJobDocuments;
|
return esJobDocuments;
|
||||||
}
|
}
|
||||||
@@ -920,50 +920,50 @@ public class ESJobSearchImpl implements IESJobSearchService
|
|||||||
wrapper.limit(esJobSearch.getPageSize());
|
wrapper.limit(esJobSearch.getPageSize());
|
||||||
List<ESJobDocument> esJobDocuments = esJobDocumentMapper.selectList(wrapper);
|
List<ESJobDocument> esJobDocuments = esJobDocumentMapper.selectList(wrapper);
|
||||||
|
|
||||||
if (esJobDocuments.size() < esJobSearch.getPageSize()) {
|
// if (esJobDocuments.size() < esJobSearch.getPageSize()) {
|
||||||
// 定义要逐步放宽的搜索条件字段
|
// // 定义要逐步放宽的搜索条件字段
|
||||||
List<Runnable> relaxConditions = new ArrayList<>();
|
// List<Runnable> relaxConditions = new ArrayList<>();
|
||||||
relaxConditions.add(() -> newSearch.setArea(null));
|
// relaxConditions.add(() -> newSearch.setArea(null));
|
||||||
relaxConditions.add(() -> newSearch.setExperience(null));
|
// relaxConditions.add(() -> newSearch.setExperience(null));
|
||||||
relaxConditions.add(() -> newSearch.setMaxSalary(null));
|
// relaxConditions.add(() -> newSearch.setMaxSalary(null));
|
||||||
relaxConditions.add(() -> newSearch.setMinSalary(null));
|
// relaxConditions.add(() -> newSearch.setMinSalary(null));
|
||||||
relaxConditions.add(() -> newSearch.setEducation(null));
|
// relaxConditions.add(() -> newSearch.setEducation(null));
|
||||||
relaxConditions.add(()-> newSearch.setJobTitle(null));
|
// relaxConditions.add(()-> newSearch.setJobTitle(null));
|
||||||
// 保存所有查询到的文档
|
// // 保存所有查询到的文档
|
||||||
List<ESJobDocument> allDocuments = new ArrayList<>(esJobDocuments);
|
// List<ESJobDocument> allDocuments = new ArrayList<>(esJobDocuments);
|
||||||
|
//
|
||||||
// 记录已经放宽的条件数量
|
// // 记录已经放宽的条件数量
|
||||||
int relaxedConditions = 0;
|
// int relaxedConditions = 0;
|
||||||
|
//
|
||||||
// 继续放宽条件直到满足分页或所有条件都已放宽
|
// // 继续放宽条件直到满足分页或所有条件都已放宽
|
||||||
while (allDocuments.size() < esJobSearch.getPageSize()
|
// while (allDocuments.size() < esJobSearch.getPageSize()
|
||||||
&& relaxedConditions < relaxConditions.size()) {
|
// && relaxedConditions < relaxConditions.size()) {
|
||||||
// 放宽下一个条件
|
// // 放宽下一个条件
|
||||||
relaxConditions.get(relaxedConditions).run();
|
// relaxConditions.get(relaxedConditions).run();
|
||||||
relaxedConditions++;
|
// relaxedConditions++;
|
||||||
|
//
|
||||||
// 查询新增的文档(不包含之前已经查询到的)
|
// // 查询新增的文档(不包含之前已经查询到的)
|
||||||
wrapper = getWrapper(newSearch, jobIds);
|
// wrapper = getWrapper(newSearch, jobIds);
|
||||||
wrapper.limit(esJobSearch.getPageSize() - allDocuments.size());
|
// wrapper.limit(esJobSearch.getPageSize() - allDocuments.size());
|
||||||
if (!allDocuments.isEmpty()) {
|
// if (!allDocuments.isEmpty()) {
|
||||||
// 排除已经查询到的文档ID
|
// // 排除已经查询到的文档ID
|
||||||
Set<String> existingIds = allDocuments.stream()
|
// Set<String> existingIds = allDocuments.stream()
|
||||||
.map(ESJobDocument::getId)
|
// .map(ESJobDocument::getId)
|
||||||
.collect(Collectors.toSet());
|
// .collect(Collectors.toSet());
|
||||||
wrapper.not().in(ESJobDocument::getId, existingIds);
|
// wrapper.not().in(ESJobDocument::getId, existingIds);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
List<ESJobDocument> newDocuments = esJobDocumentMapper.selectList(wrapper);
|
// List<ESJobDocument> newDocuments = esJobDocumentMapper.selectList(wrapper);
|
||||||
allDocuments.addAll(newDocuments);
|
// allDocuments.addAll(newDocuments);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// 如果总数超过分页大小,截取所需数量
|
// // 如果总数超过分页大小,截取所需数量
|
||||||
if (allDocuments.size() > esJobSearch.getPageSize()) {
|
// if (allDocuments.size() > esJobSearch.getPageSize()) {
|
||||||
esJobDocuments = allDocuments.subList(0, esJobSearch.getPageSize());
|
// esJobDocuments = allDocuments.subList(0, esJobSearch.getPageSize());
|
||||||
} else {
|
// } else {
|
||||||
esJobDocuments = allDocuments;
|
// esJobDocuments = allDocuments;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
return esJobDocuments;
|
return esJobDocuments;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import java.util.stream.Collectors;
|
|||||||
import com.alibaba.fastjson2.JSONArray;
|
import com.alibaba.fastjson2.JSONArray;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||||
import com.ruoyi.cms.constant.CommonConstant;
|
import com.ruoyi.cms.constant.CommonConstant;
|
||||||
import com.ruoyi.cms.domain.SubwayLine;
|
|
||||||
import com.ruoyi.cms.util.JobTitleUtils;
|
import com.ruoyi.cms.util.JobTitleUtils;
|
||||||
|
import com.ruoyi.common.constant.CacheConstants;
|
||||||
import com.ruoyi.common.core.domain.TreeSelect;
|
import com.ruoyi.common.core.domain.TreeSelect;
|
||||||
import com.ruoyi.common.core.redis.RedisCache;
|
import com.ruoyi.common.core.redis.RedisCache;
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
@@ -30,6 +30,8 @@ public class JobTitleServiceImpl extends ServiceImpl<JobTitleMapper,JobTitle> im
|
|||||||
{
|
{
|
||||||
@Autowired
|
@Autowired
|
||||||
private JobTitleMapper jobTitleMapper;
|
private JobTitleMapper jobTitleMapper;
|
||||||
|
@Autowired
|
||||||
|
private RedisCache redisCache;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询岗位
|
* 查询岗位
|
||||||
@@ -228,4 +230,19 @@ public class JobTitleServiceImpl extends ServiceImpl<JobTitleMapper,JobTitle> im
|
|||||||
public List<JobTitle> levelOne() {
|
public List<JobTitle> levelOne() {
|
||||||
return jobTitleMapper.selectList(Wrappers.<JobTitle>lambdaQuery().eq(JobTitle::getParentId, 0l));
|
return jobTitleMapper.selectList(Wrappers.<JobTitle>lambdaQuery().eq(JobTitle::getParentId, 0l));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> jobTitleNameSets(){
|
||||||
|
Set<String> labelSet = redisCache.getCacheObject(CacheConstants.JOB_LABEL_REDIS_KEY);
|
||||||
|
if(labelSet == null || labelSet.isEmpty()){
|
||||||
|
List<JobTitle> list = jobTitleMapper.selectJobTitleList(new JobTitle());
|
||||||
|
labelSet = list.stream()
|
||||||
|
.map(JobTitle::getJobName)
|
||||||
|
.filter(label -> label != null && !label.trim().isEmpty())
|
||||||
|
.map(String::trim)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
redisCache.setCacheObject(CacheConstants.JOB_LABEL_REDIS_KEY, labelSet);
|
||||||
|
}
|
||||||
|
return labelSet;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package com.ruoyi.cms.util.ik;
|
||||||
|
|
||||||
|
import org.elasticsearch.client.RequestOptions;
|
||||||
|
import org.elasticsearch.client.RestHighLevelClient;
|
||||||
|
import org.elasticsearch.client.indices.AnalyzeRequest;
|
||||||
|
import org.elasticsearch.client.indices.AnalyzeResponse;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class EsAnalyzeUtil {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private RestHighLevelClient restHighLevelClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取分词Token,携带偏移量
|
||||||
|
* @param text 原文
|
||||||
|
* @param analyzer ik_max_word / ik_smart
|
||||||
|
*/
|
||||||
|
public List<TokenItem> analyze(String text, String analyzer) {
|
||||||
|
AnalyzeRequest request = AnalyzeRequest.withGlobalAnalyzer(analyzer, text);
|
||||||
|
try {
|
||||||
|
AnalyzeResponse response = restHighLevelClient.indices().analyze(request, RequestOptions.DEFAULT);
|
||||||
|
return response.getTokens().stream()
|
||||||
|
.map(token -> {
|
||||||
|
TokenItem item = new TokenItem();
|
||||||
|
item.term = token.getTerm();
|
||||||
|
item.startOffset = token.getStartOffset();
|
||||||
|
item.endOffset = token.getEndOffset();
|
||||||
|
return item;
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException("调用ES分词接口异常", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TokenItem {
|
||||||
|
private String term;
|
||||||
|
private int startOffset;
|
||||||
|
private int endOffset;
|
||||||
|
|
||||||
|
public String getLexemeText() {
|
||||||
|
return term;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTerm() {
|
||||||
|
return term;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getStartOffset() {
|
||||||
|
return startOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getEndOffset() {
|
||||||
|
return endOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,349 @@
|
|||||||
|
package com.ruoyi.cms.util.ik;
|
||||||
|
|
||||||
|
import com.ruoyi.cms.domain.ik.JobSearchCondition;
|
||||||
|
import com.ruoyi.cms.domain.ik.ParserDictDTO;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
|
||||||
|
public class TextConditionParserUtil {
|
||||||
|
|
||||||
|
// ====================== 正则规则【不变】 ======================
|
||||||
|
private static final Pattern YEAR_PATTERN = Pattern.compile("(\\d+)\\s*-\\s*(\\d+)年|(\\d+)年以上|(\\d+)年以内");
|
||||||
|
/** 区间 3000~6000|3k-6k|3千~6千 */
|
||||||
|
private static final Pattern P_SALARY_RANGE = Pattern.compile(
|
||||||
|
"(\\d+)\\s*[-~~]\\s*(\\d+)|(\\d+)k\\s*[-~~]\\s*(\\d+)k|(\\d+)千\\s*[-~~]\\s*(\\d+)千"
|
||||||
|
);
|
||||||
|
/** 不低于 / 以上 >= */
|
||||||
|
private static final Pattern P_SALARY_GE = Pattern.compile(
|
||||||
|
"(月薪|薪资|工资)不低于\\s*(\\d+)(k|千)?|(\\d+)(k|千)?\\s*(以上)"
|
||||||
|
);
|
||||||
|
/** 不高于 / 以下 <= */
|
||||||
|
private static final Pattern P_SALARY_LE = Pattern.compile(
|
||||||
|
"(月薪|薪资|工资)不高于\\s*(\\d+)(k|千)?|(\\d+)(k|千)?\\s*(以下)"
|
||||||
|
);
|
||||||
|
/** 精准薪资:月薪5000、工资5000、薪资5000 */
|
||||||
|
private static final Pattern P_SALARY_NUM = Pattern.compile(
|
||||||
|
"(月薪|薪资|工资)\\s*(\\d+)(k|千)?"
|
||||||
|
);
|
||||||
|
|
||||||
|
/** 精准中文薪资:月薪五千、薪资一万【独立正则,不和阿拉伯混合!重点修复】 */
|
||||||
|
private static final Pattern P_SALARY_CHINESE = Pattern.compile(
|
||||||
|
"(月薪|薪资|工资)\\s*(一|二|三|四|五|六|七|八|九|十)(千|万)"
|
||||||
|
);
|
||||||
|
|
||||||
|
//中文数字映射表
|
||||||
|
private static Long getChineseNum(String numChar, String unit) {
|
||||||
|
int num;
|
||||||
|
switch (numChar) {
|
||||||
|
case "一": num = 1; break;
|
||||||
|
case "二": num = 2; break;
|
||||||
|
case "三": num = 3; break;
|
||||||
|
case "四": num = 4; break;
|
||||||
|
case "五": num = 5; break;
|
||||||
|
case "六": num = 6; break;
|
||||||
|
case "七": num = 7; break;
|
||||||
|
case "八": num = 8; break;
|
||||||
|
case "九": num = 9; break;
|
||||||
|
case "十": num = 10; break;
|
||||||
|
default: return null;
|
||||||
|
}
|
||||||
|
Long base = (long) num;
|
||||||
|
if ("千".equals(unit)) {
|
||||||
|
base = base * 1000L;
|
||||||
|
} else if ("万".equals(unit)) {
|
||||||
|
base = base * 10000L;
|
||||||
|
}
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 匹配单独年限:3年、5年工作经验
|
||||||
|
private static final Pattern SINGLE_YEAR_PATTERN = Pattern.compile("(\\d+)年");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析入口,词典由上层Service传入(来自Redis)
|
||||||
|
* @param input 用户输入原文
|
||||||
|
* @param tokenList ES分词结果
|
||||||
|
* @param dictDTO 字典数据(Redis加载)
|
||||||
|
*/
|
||||||
|
public static JobSearchCondition parse(String input,
|
||||||
|
List<EsAnalyzeUtil.TokenItem> tokenList,
|
||||||
|
ParserDictDTO dictDTO) {
|
||||||
|
if (input == null || input.trim().isEmpty()) {
|
||||||
|
return new JobSearchCondition();
|
||||||
|
}
|
||||||
|
if(dictDTO == null){
|
||||||
|
throw new RuntimeException("解析字典不能为空");
|
||||||
|
}
|
||||||
|
input = input.trim();
|
||||||
|
JobSearchCondition condition = new JobSearchCondition();
|
||||||
|
|
||||||
|
// 1.薪资、年限区间抽取
|
||||||
|
extractYearRange(input, condition);
|
||||||
|
extractSalaryRange(input, condition);
|
||||||
|
|
||||||
|
// 2.区县识别【长词优先】
|
||||||
|
extractAreaCode(input, condition, dictDTO.getAreaMap());
|
||||||
|
// 3.工作经验识别【长词优先】
|
||||||
|
extractWorkExpCode(input, condition, dictDTO.getWorkExpMap());
|
||||||
|
if (condition.getExperience() == null) {
|
||||||
|
Matcher singleYearMatcher = SINGLE_YEAR_PATTERN.matcher(input);
|
||||||
|
if (singleYearMatcher.find()) {
|
||||||
|
int year = Integer.parseInt(singleYearMatcher.group(1));
|
||||||
|
Integer expCode = convertYearToExpCode(year);
|
||||||
|
condition.setExperience(String.valueOf(expCode));
|
||||||
|
// 设置文本用于过滤jobName
|
||||||
|
condition.setWorkExpText(singleYearMatcher.group());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 4.学历识别【长词优先】
|
||||||
|
extractEducationCode(input, condition, dictDTO.getEducationMap());
|
||||||
|
|
||||||
|
// 5.拼接岗位名称,过滤已识别维度词汇
|
||||||
|
List<String> matchJobList= extractStandardJobName(input, tokenList,dictDTO.getStandardJobSet(),dictDTO.getJobIndexMap());
|
||||||
|
if (matchJobList != null && !matchJobList.isEmpty()) {
|
||||||
|
condition.setJobTitle(String.join(",", matchJobList));
|
||||||
|
} else {
|
||||||
|
condition.setJobTitle(input);
|
||||||
|
}
|
||||||
|
return condition;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void extractAreaCode(String text, JobSearchCondition condition, Map<String, Integer> areaMap) {
|
||||||
|
List<Map.Entry<String, Integer>> entryList = new ArrayList<>(areaMap.entrySet());
|
||||||
|
entryList.sort((o1, o2) -> Integer.compare(o2.getKey().length(), o1.getKey().length()));
|
||||||
|
for (Map.Entry<String, Integer> entry : entryList) {
|
||||||
|
String areaName = entry.getKey();
|
||||||
|
if (text.contains(areaName)) {
|
||||||
|
condition.setAddress(areaName);
|
||||||
|
condition.setJobLocationAreaCode(String.valueOf(entry.getValue()));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void extractWorkExpCode(String text, JobSearchCondition condition, Map<String, Integer> expMap) {
|
||||||
|
List<Map.Entry<String, Integer>> entryList = new ArrayList<>(expMap.entrySet());
|
||||||
|
entryList.sort((o1, o2) -> Integer.compare(o2.getKey().length(), o1.getKey().length()));
|
||||||
|
for (Map.Entry<String, Integer> entry : entryList) {
|
||||||
|
String key = entry.getKey();
|
||||||
|
if (text.contains(key)) {
|
||||||
|
condition.setExperience(String.valueOf(entry.getValue()));
|
||||||
|
// 新增
|
||||||
|
condition.setWorkExpText(key);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void extractEducationCode(String text, JobSearchCondition condition, Map<String, Integer> eduMap) {
|
||||||
|
List<Map.Entry<String, Integer>> entryList = new ArrayList<>(eduMap.entrySet());
|
||||||
|
entryList.sort((o1, o2) -> Integer.compare(o2.getKey().length(), o1.getKey().length()));
|
||||||
|
for (Map.Entry<String, Integer> entry : entryList) {
|
||||||
|
String key = entry.getKey();
|
||||||
|
if (text.contains(key)) {
|
||||||
|
condition.setEducation(String.valueOf(entry.getValue()));
|
||||||
|
condition.setEducationText(key);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void extractYearRange(String text, JobSearchCondition condition) {
|
||||||
|
Matcher matcher = YEAR_PATTERN.matcher(text);
|
||||||
|
if (matcher.find()) {
|
||||||
|
if (matcher.group(1) != null && matcher.group(2) != null) {
|
||||||
|
condition.setWorkYearMin(Integer.parseInt(matcher.group(1)));
|
||||||
|
condition.setWorkYearMax(Integer.parseInt(matcher.group(2)));
|
||||||
|
} else if (matcher.group(3) != null) {
|
||||||
|
condition.setWorkYearMin(Integer.parseInt(matcher.group(3)));
|
||||||
|
} else if (matcher.group(4) != null) {
|
||||||
|
condition.setWorkYearMax(Integer.parseInt(matcher.group(4)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void extractSalaryRange(String text, JobSearchCondition condition) {
|
||||||
|
text = text.trim();
|
||||||
|
Matcher m;
|
||||||
|
|
||||||
|
// 1.优先匹配区间
|
||||||
|
m = P_SALARY_RANGE.matcher(text);
|
||||||
|
if (m.find()) {
|
||||||
|
if (m.group(1) != null && m.group(2) != null) {
|
||||||
|
condition.setMinSalary(Long.parseLong(m.group(1)));
|
||||||
|
condition.setMaxSalary(Long.parseLong(m.group(2)));
|
||||||
|
} else if (m.group(3) != null && m.group(4) != null) {
|
||||||
|
// 3k~6k
|
||||||
|
Long num1 = Long.parseLong(m.group(3)) * 1000L;
|
||||||
|
Long num2 = Long.parseLong(m.group(4)) * 1000L;
|
||||||
|
condition.setMinSalary(num1);
|
||||||
|
condition.setMaxSalary(num2);
|
||||||
|
} else if (m.group(5) != null && m.group(6) != null) {
|
||||||
|
Long num1 = Long.parseLong(m.group(5)) * 1000L;
|
||||||
|
Long num2 = Long.parseLong(m.group(6)) * 1000L;
|
||||||
|
condition.setMinSalary(num1);
|
||||||
|
condition.setMaxSalary(num2);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2.匹配 >=
|
||||||
|
m = P_SALARY_GE.matcher(text);
|
||||||
|
if (m.find()) {
|
||||||
|
String numStr = null;
|
||||||
|
if (m.group(2) != null) numStr = m.group(2);
|
||||||
|
if (m.group(4) != null) numStr = m.group(4);
|
||||||
|
if (numStr != null) {
|
||||||
|
// 字符串转Long
|
||||||
|
Long num = Long.parseLong(numStr);
|
||||||
|
// 判断单位 k / 千,乘以1000
|
||||||
|
if ("k".equals(m.group(3)) || "千".equals(m.group(3))
|
||||||
|
|| "k".equals(m.group(5)) || "千".equals(m.group(5))) {
|
||||||
|
num = num * 1000L;
|
||||||
|
}
|
||||||
|
condition.setMinSalary(num);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3.匹配 <=
|
||||||
|
m = P_SALARY_LE.matcher(text);
|
||||||
|
if (m.find()) {
|
||||||
|
String numStr = null;
|
||||||
|
if (m.group(2) != null) numStr = m.group(2);
|
||||||
|
if (m.group(4) != null) numStr = m.group(4);
|
||||||
|
if (numStr != null) {
|
||||||
|
Long num = Long.parseLong(numStr);
|
||||||
|
if ("k".equals(m.group(3)) || "千".equals(m.group(3))
|
||||||
|
|| "k".equals(m.group(5)) || "千".equals(m.group(5))) {
|
||||||
|
num = num * 1000L;
|
||||||
|
}
|
||||||
|
condition.setMaxSalary(num);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4.阿拉伯数字薪资
|
||||||
|
m = P_SALARY_NUM.matcher(text);
|
||||||
|
if (m.find()) {
|
||||||
|
Long num = safeParseLong(m.group(2));
|
||||||
|
if (num != null) {
|
||||||
|
if ("k".equals(m.group(3)) || "千".equals(m.group(3))) {
|
||||||
|
num = num * 1000L;
|
||||||
|
}
|
||||||
|
condition.setMinSalary(num);
|
||||||
|
//condition.setMaxSalary(num);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5.中文薪资【月薪五千】单独匹配
|
||||||
|
m = P_SALARY_CHINESE.matcher(text);
|
||||||
|
if (m.find()) {
|
||||||
|
Long num = getChineseNum(m.group(2), m.group(3));
|
||||||
|
condition.setMinSalary(num);
|
||||||
|
//condition.setMaxSalary(num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据工作年限数字,换算成 workExpCode
|
||||||
|
*/
|
||||||
|
private static Integer convertYearToExpCode(int year) {
|
||||||
|
if (year < 1) {
|
||||||
|
return 3;
|
||||||
|
} else if (year <= 3) {
|
||||||
|
return 4;
|
||||||
|
} else if (year <= 5) {
|
||||||
|
return 5;
|
||||||
|
} else if (year <= 10) {
|
||||||
|
return 6;
|
||||||
|
} else {
|
||||||
|
return 7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 正向匹配国标岗位名称(长词优先)
|
||||||
|
* @param input 用户原始输入文本
|
||||||
|
* @param standardJobSet 国标岗位集合
|
||||||
|
* @return 匹配到的岗位名称,无匹配返回null
|
||||||
|
*/
|
||||||
|
private static List<String> extractStandardJobName(String input,List<EsAnalyzeUtil.TokenItem> tokenList, Set<String> standardJobSet, Map<String,String> jobIndexMap) {
|
||||||
|
if (standardJobSet == null || standardJobSet.isEmpty() || jobIndexMap == null || jobIndexMap.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String text = input.replace("/", "");
|
||||||
|
List<String> jobList = new ArrayList<>(standardJobSet);
|
||||||
|
// 长名称优先,优先匹配更长岗位,避免短词根优先命中
|
||||||
|
jobList.sort((s1, s2) -> Integer.compare(s2.length(), s1.length()));
|
||||||
|
final int MAX_MATCH_SIZE = 5;
|
||||||
|
|
||||||
|
for (String jobName : jobList) {
|
||||||
|
if (text.contains(jobName)) {
|
||||||
|
return Collections.singletonList(jobName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<String> matchSet = new HashSet<>();
|
||||||
|
if (tokenList != null && !tokenList.isEmpty()) {
|
||||||
|
for (EsAnalyzeUtil.TokenItem token : tokenList) {
|
||||||
|
String word = token.getLexemeText().trim();
|
||||||
|
if (word.length() < 2) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (String jobName : jobList) {
|
||||||
|
if (jobName.contains(word)) {
|
||||||
|
matchSet.add(jobName);
|
||||||
|
if (matchSet.size() >= MAX_MATCH_SIZE) {
|
||||||
|
return new ArrayList<>(matchSet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!matchSet.isEmpty()) {
|
||||||
|
return new ArrayList<>(matchSet);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isFilterWord(String word, JobSearchCondition condition) {
|
||||||
|
// 基础过滤词
|
||||||
|
if (word.matches("\\d+") || new ArrayList<>(Arrays.asList(
|
||||||
|
"k", "千", "年", "月薪", "薪资", "工资",
|
||||||
|
"以上", "以下", "的", "不低于", "不高于",
|
||||||
|
"学历", "工作经验"
|
||||||
|
)).contains(word)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// 过滤区县
|
||||||
|
if (condition.getAddress() != null && condition.getAddress().contains(word)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// 过滤学历文本(本科、大专...)
|
||||||
|
if (condition.getEducationText() != null && condition.getEducationText().contains(word)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// 过滤经验文本(1-3年、应届毕业生...)
|
||||||
|
if (condition.getWorkExpText() != null && condition.getWorkExpText().contains(word)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Long safeParseLong(String str) {
|
||||||
|
if (str == null || str.trim().isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return Long.parseLong(str);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -54,4 +54,9 @@ public class CacheConstants
|
|||||||
* 刷新token
|
* 刷新token
|
||||||
*/
|
*/
|
||||||
public static final String LOGIN_SITE_REFRESH_KEY = "login_site_user:refresh_token:";
|
public static final String LOGIN_SITE_REFRESH_KEY = "login_site_user:refresh_token:";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 国标岗位名称
|
||||||
|
*/
|
||||||
|
public static final String JOB_LABEL_REDIS_KEY = "dict:job_title:label_list";
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user