Authored by Gino Zhang

搜索权重支持动态配置

... ... @@ -2,6 +2,8 @@ package com.yoho.search.dal;
import com.yoho.search.dal.model.DynamicRuleDetails;
import java.util.List;
/**
* Created by ginozhang on 2016/12/19.
*/
... ... @@ -11,6 +13,8 @@ public interface DynamicRuleDetailsMapper {
DynamicRuleDetails selectById(Integer id);
List<DynamicRuleDetails> selectByRuleIdList(List<Integer> ruleIdList);
void insert(DynamicRuleDetails dynamicRuleDetails);
void updateById(DynamicRuleDetails dynamicRuleDetails);
... ...
... ... @@ -2,6 +2,8 @@ package com.yoho.search.dal;
import com.yoho.search.dal.model.DynamicRule;
import java.util.List;
/**
* Created by ginozhang on 2016/12/19.
*/
... ... @@ -11,6 +13,8 @@ public interface DynamicRuleMapper {
DynamicRule selectById(Integer id);
List<DynamicRule> selectByRuleIdList(List<Integer> ruleIdList);
void insert(DynamicRule dynamicRule);
void updateById(DynamicRule dynamicRule);
... ...
... ... @@ -2,6 +2,8 @@ package com.yoho.search.dal;
import com.yoho.search.dal.model.DynamicRulePageRel;
import java.util.List;
/**
* Created by ginozhang on 2016/12/19.
*/
... ... @@ -11,6 +13,8 @@ public interface DynamicRulePageRelMapper {
DynamicRulePageRel selectById(Integer id);
List<DynamicRulePageRel> selectAll();
void insert(DynamicRulePageRel dynamicRulePageRel);
void updateById(DynamicRulePageRel dynamicRulePageRel);
... ...
... ... @@ -25,6 +25,14 @@
select <include refid="DynamicRuleDetails_Column_List"/> from dynamic_rule_details where id = #{id, jdbcType=INTEGER}
</select>
<select id="selectByRuleIdList" resultMap="DynamicRuleDetailsResultMap">
select <include refid="DynamicRuleDetails_Column_List"/> from dynamic_rule_details where rule_id in
<foreach item="item" index="index" collection="list" open="("
separator="," close=")">
#{item}
</foreach>
</select>
<update id="updateById" parameterType="com.yoho.search.dal.model.DynamicRuleDetails">
update dynamic_rule_details
set rule_id = #{ruleId, jdbcType=INTEGER},
... ...
... ... @@ -25,10 +25,18 @@
#{boost, jdbcType=INTEGER})
</insert>
<select id="selectById" resultMap="BaseResultMap" parameterType="java.lang.Integer">
<select id="selectById" resultMap="DynamicRuleResultMap" parameterType="java.lang.Integer">
select <include refid="DynamicRule_Column_List"/> from dynamic_rule where id = #{id, jdbcType=INTEGER}
</select>
<select id="selectByRuleIdList" resultMap="DynamicRuleResultMap">
select <include refid="DynamicRule_Column_List"/> from dynamic_rule where id in
<foreach item="item" index="index" collection="list" open="("
separator="," close=")">
#{item}
</foreach>
</select>
<update id="updateById" parameterType="com.yoho.search.dal.model.DynamicRule">
update dynamic_rule
set name = #{name,jdbcType=VARCHAR},
... ...
... ... @@ -23,6 +23,10 @@
select <include refid="DynamicRulePageRel_Column_List"/> from dynamic_rule_page_rel where id = #{id, jdbcType=INTEGER}
</select>
<select id="selectAll" resultMap="DynamicRulePageRelResultMap">
select <include refid="DynamicRulePageRel_Column_List"/> from dynamic_rule_page_rel
</select>
<update id="updateById" parameterType="com.yoho.search.dal.model.DynamicRulePageRel">
update dynamic_rule_page_rel
set rule_id = #{ruleId, jdbcType=INTEGER},
... ...
... ... @@ -6,6 +6,7 @@ import com.yoho.error.event.SearchEvent;
import com.yoho.search.base.utils.ConvertUtils;
import com.yoho.search.base.utils.EventReportEnum;
import com.yoho.search.base.utils.ISearchConstants;
import com.yoho.search.consumer.index.increment.rule.DynamicRuleManager;
import com.yoho.search.consumer.service.base.DynamicRuleDetailsService;
import com.yoho.search.core.es.utils.IgnoreSomeException;
import com.yoho.search.dal.model.DynamicRuleDetails;
... ... @@ -27,6 +28,9 @@ public class DynamicRuleDetailsMqListener extends AbstractMqListener implements
@Autowired
private DynamicRuleDetailsService dynamicRuleDetailsService;
@Autowired
private DynamicRuleManager dynamicRuleManager;
@Override
public void onMessage(Message message, Channel channel) throws Exception {
try {
... ... @@ -40,6 +44,8 @@ public class DynamicRuleDetailsMqListener extends AbstractMqListener implements
} else {
updateData(json.getObject("data", Map.class));
}
dynamicRuleManager.notifyChange();
} catch (Exception e) {
publisher.publishEvent(new SearchEvent(EventReportEnum.ESWORDDEF_MQLISTENER_ONMESSAGE.getEventName(),
EventReportEnum.ESWORDDEF_MQLISTENER_ONMESSAGE.getFunctionName(),
... ...
... ... @@ -6,6 +6,7 @@ import com.yoho.error.event.SearchEvent;
import com.yoho.search.base.utils.ConvertUtils;
import com.yoho.search.base.utils.EventReportEnum;
import com.yoho.search.base.utils.ISearchConstants;
import com.yoho.search.consumer.index.increment.rule.DynamicRuleManager;
import com.yoho.search.consumer.service.base.DynamicRuleService;
import com.yoho.search.core.es.utils.IgnoreSomeException;
import com.yoho.search.dal.model.DynamicRule;
... ... @@ -27,6 +28,9 @@ public class DynamicRuleMqListener extends AbstractMqListener implements Channel
@Autowired
private DynamicRuleService dynamicRuleService;
@Autowired
private DynamicRuleManager dynamicRuleManager;
@Override
public void onMessage(Message message, Channel channel) throws Exception {
try {
... ... @@ -40,6 +44,8 @@ public class DynamicRuleMqListener extends AbstractMqListener implements Channel
} else {
updateData(json.getObject("data", Map.class));
}
dynamicRuleManager.notifyChange();
} catch (Exception e) {
publisher.publishEvent(new SearchEvent(EventReportEnum.ESWORDDEF_MQLISTENER_ONMESSAGE.getEventName(),
EventReportEnum.ESWORDDEF_MQLISTENER_ONMESSAGE.getFunctionName(),
... ...
... ... @@ -6,6 +6,7 @@ import com.yoho.error.event.SearchEvent;
import com.yoho.search.base.utils.ConvertUtils;
import com.yoho.search.base.utils.EventReportEnum;
import com.yoho.search.base.utils.ISearchConstants;
import com.yoho.search.consumer.index.increment.rule.DynamicRuleManager;
import com.yoho.search.consumer.service.base.DynamicRulePageRelService;
import com.yoho.search.core.es.utils.IgnoreSomeException;
import com.yoho.search.dal.model.DynamicRulePageRel;
... ... @@ -27,6 +28,9 @@ public class DynamicRulePageRelMqListener extends AbstractMqListener implements
@Autowired
private DynamicRulePageRelService dynamicRulePageRelService;
@Autowired
private DynamicRuleManager dynamicRuleManager;
@Override
public void onMessage(Message message, Channel channel) throws Exception {
try {
... ... @@ -40,6 +44,8 @@ public class DynamicRulePageRelMqListener extends AbstractMqListener implements
} else {
updateData(json.getObject("data", Map.class));
}
dynamicRuleManager.notifyChange();
} catch (Exception e) {
publisher.publishEvent(new SearchEvent(EventReportEnum.ESWORDDEF_MQLISTENER_ONMESSAGE.getEventName(),
EventReportEnum.ESWORDDEF_MQLISTENER_ONMESSAGE.getFunctionName(),
... ...
package com.yoho.search.consumer.index.increment.rule;
import com.yoho.search.consumer.service.base.DynamicRuleDetailsService;
import com.yoho.search.consumer.service.base.DynamicRulePageRelService;
import com.yoho.search.consumer.service.base.DynamicRuleService;
import com.yoho.search.dal.model.DynamicRule;
import com.yoho.search.dal.model.DynamicRuleDetails;
import com.yoho.search.dal.model.DynamicRulePageRel;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* Created by ginozhang on 2016/12/19.
*/
@Component
public class DynamicRuleGenerator {
private static final Logger logger = LoggerFactory.getLogger(DynamicRuleGenerator.class);
private static final int COMPOUND_RULE_TYPE = 2;
private static final int SIMPLE_RULE_TYPE = 1;
private static final int SEARCHFIELD_RULE_TYPE = 3;
private static final int RELEASED_STATUS = 1;
private static final int SEARCH_FIELD_USAGE = 1;
private static final int SHOULD_FIELD_USAGE = 2;
// search_rule_%s_%s_%s_cfg -> search_rule_<pageType>_<usageType>_<status>_cfg -> search_rule_searchpage_searchfields_released_cfg
private static final String RULE_KEY_FORMAT = "search_rule_%s_%s_%s_cfg";
private static Map<Integer, String> pageTypeMap = new HashMap<>();
private static Map<Integer, String> usageTypeMap = new HashMap<>();
private static Map<Integer, String> statusTypeMap = new HashMap<>();
@Autowired
private DynamicRuleService dynamicRuleService;
@Autowired
private DynamicRuleDetailsService dynamicRuleDetailsService;
@Autowired
private DynamicRulePageRelService dynamicRulePageRelService;
@Autowired
private DynamicRulePersistenceService dynamicRulePersistenceService;
static {
pageTypeMap.put(1, "brandpage");
pageTypeMap.put(2, "sortpage");
pageTypeMap.put(3, "searchpage");
pageTypeMap.put(4, "newpage");
//usageTypeMap.put(SEARCH_FIELD_USAGE, "searchfields");
usageTypeMap.put(SHOULD_FIELD_USAGE, "shouldfields");
statusTypeMap.put(0, "tested");
statusTypeMap.put(1, "released");
}
public synchronized void generate() {
try {
long begin = System.currentTimeMillis();
logger.info("[func=generate][begin={}]", begin);
Map<String, String> ruleValueMap = generateSearchRules();
logger.info("[func=generate][ruleValueMap={}]", ruleValueMap);
dynamicRulePersistenceService.persistenceRules(ruleValueMap);
logger.info("[func=generate][cost={}]", System.currentTimeMillis() - begin);
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
private Map<String, String> generateSearchRules() {
long begin = System.currentTimeMillis();
logger.info("[func=generateSearchRules][begin={}]", begin);
Map<String, String> ruleValueMap = new HashMap<>();
List<DynamicRulePageRel> pageRelList = dynamicRulePageRelService.selectAll();
if (CollectionUtils.isEmpty(pageRelList)) {
setAllDefaultRuleValues(ruleValueMap);
logger.info("[func=generateSearchRules][cost={}]", System.currentTimeMillis() - begin);
return ruleValueMap;
}
List<Integer> ruleIdList = pageRelList.stream().map(DynamicRulePageRel::getRuleId).collect(Collectors.toList());
List<DynamicRule> ruleList = dynamicRuleService.selectByRuleIdList(ruleIdList);
if (CollectionUtils.isEmpty(ruleList)) {
setAllDefaultRuleValues(ruleValueMap);
logger.info("[func=generateSearchRules][cost={}]", System.currentTimeMillis() - begin);
return ruleValueMap;
}
List<Integer> ruleIdListForDetails = ruleList.stream().filter(rule -> rule.getType() == COMPOUND_RULE_TYPE).map(DynamicRule::getId).collect(Collectors.toList());
List<DynamicRuleDetails> ruleDetailsList = dynamicRuleDetailsService.selectByRuleIdList(ruleIdListForDetails);
int ruleDetailsSize = ruleDetailsList != null ? ruleDetailsList.size() : 0;
logger.info("[func=generateSearchRules][pageRelSize={}][ruleSize={}][detailsSize={}]", pageRelList.size(), ruleIdList.size(), ruleDetailsSize);
ruleValueMap.putAll(generateSearchRules(pageRelList, ruleList, ruleDetailsList, false));
ruleValueMap.putAll(generateSearchRules(pageRelList, ruleList, ruleDetailsList, true));
logger.info("[func=generateSearchRules][cost={}]", System.currentTimeMillis() - begin);
return ruleValueMap;
}
private Map<String, String> generateSearchRules(List<DynamicRulePageRel> pageRelList, List<DynamicRule> ruleList, List<DynamicRuleDetails> ruleDetailsList, boolean isForReleased) {
Map<String, String> ruleValueMap = new HashMap<>();
Map<Integer, DynamicRule> ruleMap = ruleList.stream().filter(rule -> !isForReleased || rule.getStatus() == RELEASED_STATUS)
.collect(Collectors.toMap(DynamicRule::getId, rule -> rule));
Map<Integer, List<DynamicRulePageRel>> pageRelMap = pageRelList.stream().filter(pageRel -> !isForReleased || pageRel.getStatus() == RELEASED_STATUS)
.collect(Collectors.groupingBy(DynamicRulePageRel::getPageType));
for (Integer pageType : pageTypeMap.keySet()) {
List<DynamicRulePageRel> pageRelListForType = pageRelMap.get(pageType);
if (CollectionUtils.isEmpty(pageRelListForType)) {
setDefaultRuleValues(ruleValueMap, pageType, isForReleased);
continue;
}
List<DynamicRule> ruleListForType = pageRelListForType.stream().filter(pageRel -> ruleMap.containsKey(pageRel.getRuleId())).map(pageRel -> ruleMap.get(pageRel.getRuleId())).collect(Collectors.toList());
if (CollectionUtils.isEmpty(ruleListForType)) {
setDefaultRuleValues(ruleValueMap, pageType, isForReleased);
continue;
}
// Optional<DynamicRule> searchFieldRule = ruleListForType.stream().filter(rule -> rule.getType() == SEARCHFIELD_RULE_TYPE).findAny();
// if (searchFieldRule.isPresent()) {
// // TODO: 处理SearchField
// } else {
// releasedRules.put(getRuleKey(pageType, SEARCH_FIELD_USAGE, true), "-1");
// }
// TODO: 暂时只支持Simple的规则 复合规则后续实现
List<DynamicRule> rulesForSimple = ruleListForType.stream().filter(rule -> rule.getType() == SIMPLE_RULE_TYPE).collect(Collectors.toList());
ruleValueMap.put(getRuleKey(pageType, SHOULD_FIELD_USAGE, isForReleased), getShouldRuleValue(rulesForSimple));
}
return ruleValueMap;
}
private String getShouldRuleValue(List<DynamicRule> rulesForSimple) {
if (CollectionUtils.isEmpty(rulesForSimple)) {
return "-1";
}
StringBuilder sb = new StringBuilder();
rulesForSimple.forEach(rule -> {
sb.append(rule.getField()).append("|").append(rule.getValues()).append("|").append(rule.getBoost()).append(";");
});
return sb.toString();
}
private void setAllDefaultRuleValues(Map<String, String> ruleValueMap) {
for (Map.Entry<Integer, String> pageTypeEntry : pageTypeMap.entrySet()) {
for (Map.Entry<Integer, String> usageTypeEntry : usageTypeMap.entrySet()) {
ruleValueMap.put(getRuleKey(pageTypeEntry.getKey(), usageTypeEntry.getKey(), true), "-1");
ruleValueMap.put(getRuleKey(pageTypeEntry.getKey(), usageTypeEntry.getKey(), false), "-1");
}
}
}
private void setDefaultRuleValues(Map<String, String> ruleValueMap, Integer pageType, boolean isForReleased) {
for (Map.Entry<Integer, String> entry : usageTypeMap.entrySet()) {
ruleValueMap.put(getRuleKey(pageType, entry.getKey(), isForReleased), "-1");
}
}
private String getRuleKey(Integer pageType, Integer usageType, boolean isForReleased) {
String statusType = isForReleased ? statusTypeMap.get(1) : statusTypeMap.get(0);
return String.format(RULE_KEY_FORMAT, pageTypeMap.get(pageType), usageTypeMap.get(usageType), statusType);
}
}
... ...
package com.yoho.search.consumer.index.increment.rule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 负责处理动态规则的变更,并推送给service。
* Created by ginozhang on 2016/12/19.
*/
@Component
public class DynamicRuleManager {
private static final Logger logger = LoggerFactory.getLogger(DynamicRuleManager.class);
private static final int CHECK_PERIOD_IN_SECOND = 300;
@Autowired
private DynamicRuleGenerator dynamicRuleGenerator;
private ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
private volatile AtomicInteger version = new AtomicInteger(0);
private volatile AtomicInteger innerVersion = new AtomicInteger(0);
@PostConstruct
void init() {
scheduledExecutorService.scheduleAtFixedRate(new ReloadRuleRunnable(), 0, CHECK_PERIOD_IN_SECOND, TimeUnit.SECONDS);
}
public void notifyChange() {
version.incrementAndGet();
}
class ReloadRuleRunnable implements Runnable {
@Override
public void run() {
long begin = System.currentTimeMillis();
int currentVersion = version.get();
int innerVersionValue = innerVersion.get();
logger.info("[ReloadRuleRunnable][begin={}][version={}][innerVersion={}]", begin, currentVersion, innerVersionValue);
if (innerVersionValue < currentVersion) {
dynamicRuleGenerator.generate();
innerVersion.getAndSet(currentVersion);
logger.info("[ReloadRuleRunnable][cost={}]", System.currentTimeMillis() - begin);
}
}
}
}
... ...
package com.yoho.search.consumer.index.increment.rule;
import org.apache.curator.framework.CuratorFramework;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Map;
/**
* 负责持久化rule的值到ZK。
* Created by ginozhang on 2016/12/19.
*/
@Component
public class DynamicRulePersistenceService {
private static final Logger logger = LoggerFactory.getLogger(DynamicRulePersistenceService.class);
private static final String CONFIG_ROOT_PATH = "/yh/config";
@Resource(name = "curatorFramework")
private CuratorFramework client;
public void persistenceRules(Map<String, String> ruleValueMap) throws Exception {
if (client.checkExists().forPath(CONFIG_ROOT_PATH) == null) {
client.create().creatingParentContainersIfNeeded().forPath(CONFIG_ROOT_PATH);
}
for (Map.Entry<String, String> entry : ruleValueMap.entrySet()) {
final String path = CONFIG_ROOT_PATH + "/" + entry.getKey();
if (this.client.checkExists().forPath(path) == null) {
this.client.create().forPath(path, entry.getValue().getBytes("UTF-8"));
} else {
this.client.setData().forPath(path, entry.getValue().getBytes("UTF-8"));
}
}
}
}
... ...
... ... @@ -5,6 +5,8 @@ import com.yoho.search.dal.model.DynamicRuleDetails;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* Created by ginozhang on 2016/12/19.
*/
... ... @@ -30,6 +32,10 @@ public class DynamicRuleDetailsService {
return dynamicRuleDetailsMapper.selectById(id);
}
public List<DynamicRuleDetails> selectByRuleIdList(List<Integer> ruleIdList) {
return dynamicRuleDetailsMapper.selectByRuleIdList(ruleIdList);
}
public void insert(DynamicRuleDetails dynamicRuleDetails) {
dynamicRuleDetailsMapper.insert(dynamicRuleDetails);
}
... ...
... ... @@ -5,6 +5,8 @@ import com.yoho.search.dal.model.DynamicRulePageRel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* Created by ginozhang on 2016/12/19.
*/
... ... @@ -26,6 +28,11 @@ public class DynamicRulePageRelService {
dynamicRulePageRelMapper.delete(id);
}
public List<DynamicRulePageRel> selectAll()
{
return dynamicRulePageRelMapper.selectAll();
}
public DynamicRulePageRel selectById(Integer id) {
return dynamicRulePageRelMapper.selectById(id);
}
... ...
... ... @@ -5,6 +5,8 @@ import com.yoho.search.dal.model.DynamicRule;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* Created by ginozhang on 2016/12/19.
*/
... ... @@ -30,6 +32,10 @@ public class DynamicRuleService {
return dynamicRuleMapper.selectById(id);
}
public List<DynamicRule> selectByRuleIdList(List<Integer> ruleIdList) {
return dynamicRuleMapper.selectByRuleIdList(ruleIdList);
}
public void insert(DynamicRule dynamicRule) {
dynamicRuleMapper.insert(dynamicRule);
}
... ...