package com.winhc.phoenix.example.service.impl; import com.winhc.phoenix.example.dao.SearchDao; import com.winhc.phoenix.example.service.LegislationService; import com.winhc.phoenix.example.util.BigDecimalUtil; import com.winhc.phoenix.example.util.company.search.CompanyIndexUtils; import com.winhc.phoenix.example.vo.legislation.LegislationSearchType; import com.winhc.phoenix.example.vo.legislation.LegislationSearchVo; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.elasticsearch.common.lucene.search.function.CombineFunction; import org.elasticsearch.index.query.BoolQueryBuilder; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder; import org.elasticsearch.index.query.functionscore.ScriptScoreFunctionBuilder; import org.elasticsearch.script.Script; import org.springframework.stereotype.Service; import java.time.LocalDate; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import static org.elasticsearch.index.query.QueryBuilders.*; /** * @author: XuJiakai * 2022/9/2 11:38 */ @Slf4j @Service @AllArgsConstructor public class LegislationServiceImpl implements LegislationService { private final SearchDao searchDao; public static final String index = "legislation_info_fx_v1"; public static final String type = "legislation_info_fx_type"; private static final List highlightField = new ArrayList() {{ add("title"); add("content"); add("title.keyword"); }}; private static final String SCRIPT_TEXT = "double d = 1.0d;if(doc['effect'].value!=null){String effect =doc['effect'].value;if(effect.contains(\"法律\")){if(\"法律\".equals(effect)){if(\"全国人民代表大会\".equals(doc['agency.keyword'].value)){d+=7.9;}else if(\"全国人大常委会\".equals(doc['agency.keyword'].value)){d+=7.8;}}else if (\"法律解释\".equals(effect)){d+=6.7}}else if(\"司法解释\".equals(effect)){d+=6.5;}else if(\"司法指导性文件\".equals(effect)){d+=5.0;}else if(\"行政法规\".equals(effect)){d+=5.0;}else if(effect.contains(\"地方性法规\")){if(effect.contains(\"市地方性法规\")||effect.contains(\"州地方性法规\")){d+=4.0;}else{d+=4.5;}}else if(\"部门规章\".equals(effect)){d+=3.8}else if(\"地方政府规章\".equals(effect)){if(doc['agency.keyword'].value!=null){String agency = doc['agency.keyword'].value;if(agency.contains(\"省人民政府\")||agency.contains(\"自治区人民政府\")||agency.equals(\"北京市人民政府\")||agency.equals(\"上海市人民政府\")||agency.equals(\"天津市人民政府\")||agency.equals(\"重庆市人民政府\")){d+=3.3}else{d+=3.0}}}else if(\"地方司法文件\".equals(effect)){if(doc['agency.keyword'].value!=null){String agency = doc['agency.keyword'].value;if(agency.contains(\"高级人民法院\")||agency.contains(\"省人民检察院\")){d+=2.5;}else{d+=2.0}}}else if(effect.contains(\"规范性文件\")){if(effect.contains(\"国务院\")){d+=1.8;}else if(effect.contains(\"部门\")){d+=1.6;}else if (effect.contains(\"地方\")){if(doc['agency.keyword'].value!=null){String agency = doc['agency.keyword'].value;if(agency.contains(\"省人民政府\")||agency.contains(\"自治区人民政府\")||agency.equals(\"北京市人民政府\")||agency.equals(\"上海市人民政府\")||agency.equals(\"天津市人民政府\")||agency.equals(\"重庆市人民政府\")){d+=1.5;}else{d+=1;}}}}}String timeliness = doc['timeliness'].value;if(timeliness!=null){if(timeliness.contains(\"失效\")){d=d/2;}if(timeliness.contains(\"已被修改\")){d = d-0.3;}}long date = doc['implement_date'].value/(24l*60*60*365*1000);if(date >20){d=d + Math.abs(20-date)*params.der;}return d;"; private static QueryBuilder queryUnit(LegislationSearchType queryScope, String content) { BoolQueryBuilder boolQuery = boolQuery(); switch (queryScope) { case TITLE: boolQuery.filter(boolQuery() .should(matchQuery("title", content)) .should(termQuery("title.keyword", content)) ); boolQuery.should(disMaxQuery() .add(matchQuery("title.standard", content).minimumShouldMatch("100%").boost(20)) .add(matchQuery("title.trim", content).boost(20).minimumShouldMatch("100%")) .add(termQuery("title.keyword", content).boost(100)) .tieBreaker(0.3f) ); break; case CONTENT: boolQuery.should(disMaxQuery() .add(matchPhraseQuery("content", content).boost(25)) .add(matchQuery("content", content).boost(20).minimumShouldMatch("100%")) .add(matchQuery("content", content).boost(2)) ); break; default: boolQuery.should(boolQuery().filter(boolQuery() // .should(matchQuery("content", content).minimumShouldMatch("100%")) .should(matchQuery("title", content)) .should(termQuery("title.keyword", content)) ).boost(0)); boolQuery.should(boolQuery().filter(boolQuery() .should(matchPhraseQuery("content", content)) ).boost(25)); boolQuery.should(boolQuery().filter(boolQuery() .should(matchQuery("content", content).boost(20).minimumShouldMatch("100%")) ).boost(20)); boolQuery.should(boolQuery().filter(boolQuery() .should(matchQuery("content", content)) ).boost(2)); boolQuery.should(boolQuery().should(disMaxQuery() // .add(matchPhraseQuery("content", content).boost(25)) // .add(matchQuery("content", content).boost(20).minimumShouldMatch("100%")) // .add(matchQuery("content", content).boost(2)) .add(disMaxQuery() .add(matchQuery("title.standard", content).minimumShouldMatch("100%").boost(20)) .add(matchQuery("title.trim", content).boost(20).minimumShouldMatch("100%")) .add(termQuery("title.keyword", content).boost(100)) .tieBreaker(0.3f)) )); break; } return boolQuery; } @Override public Object search(LegislationSearchVo of) { log.info("search legislation keyword: {}", of.getContent()); BoolQueryBuilder boolQuery = boolQuery(); for (Map.Entry entry : of.getContent().entrySet()) { String content = entry.getKey(); LegislationSearchType value = entry.getValue(); for (String s : content.split(" ")) { if (StringUtils.isBlank(s)) { continue; } boolQuery.must(queryUnit(value, s)); } } LocalDate now = LocalDate.now(); int year = now.getYear(); double d = year <= 1990 ? 0 : BigDecimalUtil.div(4, year - 1990, 4); Script script = CompanyIndexUtils.getScript(SCRIPT_TEXT, new HashMap(1) { { put("der", d); } }); FunctionScoreQueryBuilder function = functionScoreQuery(boolQuery, new ScriptScoreFunctionBuilder(script)) .boostMode(CombineFunction.MULTIPLY); String preference = of.getPreference(); Object search = searchDao.search(index , type // , boolQuery , function , null , null , null , of.getFrom() , of.getSize() , preference , highlightField , null ); return search; } }