[关闭]
@yanglfyangl 2018-08-29T11:04:43.000000Z 字数 2729 阅读 491

Prediction层设计

搜索接口示例

  1. rq={!zlrerank reRankQuery=$reRankQuery reRankDocs=10000 reRankWeight=1}
  2. &reRankQuery=_val_:"ff(kpn({!edismax qf=SOU_POSITION_NAME_QUERY v='\\\"java工程师\\\"'},'10-9.5-4'),'c1')"
  3. &thirdQuery=_val_:"pedict(TestGroup, usrid, queryString, timeout)"
  4. 1. TestGroup: 预测模型的分组,未来上线多少个预测模型,就会有多少分组,业务端可以根据不同的需求调用不同分组。
  5. 2. queryString: API层将solor请求的query封装,传给pedict函数。
  6. 3. usrID:用户ID
  7. 业务端可以通过选择高效模型来提高性能。(当然在某些场景下也可以使用精度高的模型来提高用户体验)

内部设计逻辑

增加Parser

  1. addParser("pedict", new ValueSourceParser() {
  2. @Overrid
  3. public ValueSource parse(FunctionQParser fp)
  4. ValueSource v = fp.parseValueSource();
  5. ...
  6. return new PedictFunction(v, group, usrid, queryString);
  7. }
  8. });

PedictFunctionclass 的逻辑

  1. public class PedictFunction extends ValueSource {
  2. private static final MLEngineGroup engineGroup = ...
  3. private String iGroup;
  4. public PedictFunction(...) {
  5. 存下变量。
  6. }
  7. public FunctionValues getValues(final Map context, final LeafReaderContext readerContext) throws IOException {
  8. 。。。
  9. engineGroup.pedict(iGroup, ...);
  10. 。。。
  11. }

注:Solr cloud 启动时,需要设置一下配置中心地址到环境变量中。(配置中心最好是Zk,强一致性)

  1. MLEngineGroup:{
  2. private static final private static final Map<String, MLEngine> engines = new HashMap<>();
  3. MLEngineGroup engineGroup = ...
  4. private ConfigMonitor configMonitor;
  5. private FeatureReader featureReader;
  6. private getMLEngineByGroupName(String groupName){
  7. map中获取。
  8. 如果不存在,则单例创建
  9. ...
  10. {
  11. new MLEngine(featureReader,...)
  12. }
  13. }
  14. double pedict(...) {
  15. return getMLEngineByGroupName().pedict(...)
  16. }
  17. void onConfigChanged(String group){
  18. 如果对应的Group配置文件发生变化,就remove掉之前的
  19. engines.remove(group)
  20. 不在这里新建,后面会从
  21. }
  22. }
  23. // 用来读取特征。
  24. class FeatureReader:{
  25. private LocalCache localCache;
  26. private Solr solrReader;
  27. private Redis redis;
  28. //特征的读取分三个层次
  29. // 1. 本地缓存。(内存+磁盘)
  30. // 2. 本地Solr中 (离线特征会根据要求存在Solr中)
  31. // 3. Redis中
  32. T read(targetRedis, key){
  33. data = localCache.get(key);
  34. if(data) return data;
  35. if (!data && dataStoredInSolr) {
  36. data = solrReader... solor来获取
  37. }
  38. if (!data) {
  39. data = redis... redis来获取
  40. }
  41. if(data){
  42. localCache.push();
  43. }
  44. return data;
  45. }
  46. }
  47. class MLEngine:{
  48. void init(){
  49. if(!initlizedModel) {
  50. synchronized ...
  51. try{
  52. zk或配置中心获取本group的配置文件,包括:
  53. 模型所在的Redis地址。
  54. 模型所在的文件夹子(包含模型文件和配置文件)
  55. 读取模型配置文件。
  56. 读取模型
  57. 初始化 OnlineFeatureBuilder
  58. }
  59. }
  60. initlizedModel = true;
  61. if(!initlizedModelConfig) {
  62. synchronized ...
  63. try{
  64. 解析模型对应的配置文件。
  65. }
  66. }
  67. initlizedModelConfig = true;
  68. if(!initlizedQueryStringMapping) {
  69. synchronized ...
  70. try{
  71. 解析 query mapping的对应关系
  72. 用来解析 queryString
  73. }
  74. }
  75. initlizedQueryStringMapping = true;
  76. }
  77. double pedict(){
  78. double ret =0.0;
  79. try {
  80. String[] features = readFeatures(JDTYPE|CVTYPE, ...);
  81. if(JDTYPE){
  82. return OnlineFeatureBuilder.build(...)
  83. } else {
  84. return OnlineFeatureBuilder.build(...)
  85. }
  86. }
  87. final{
  88. ...
  89. }
  90. return ret;
  91. }
  92. ....
  93. }

目前方案中性能的优化点

  • 增加了本地缓存(本地内存+本地磁盘)
  • 如果特征存入了Solr,则从Solr中取对应的特征。
  • 支持小批量查询(比如,20个为一组进行计算),如果超时,则返回。
  • 支持快速模型切换。(如果对性能有更高的要求,可以切换成高速模型)

目前方案中灵活性的体现

  • 模型上线只需要在配置中心增加配置文件,就可以按名字调用。
  • 模型中的特征数据并不依赖redis或solr,只要有就可以用。
  • 如果发现模型有问题,只需要更新配置,就可以全部替换,下一次查询时生效。
  • 类似A/B test或灰度等,是不需要重启集群的,只需要进行相应的配置就可以。

什么情况之下需要改动代码升级:

  • 目前的模型算法中公式需要增加(一般这是由算法团队主导的)

外部依赖有哪些

  • 模型文件和配置需要放到一个高可用的地方。
  • 配置中心需要高可用(最好强一致性,根据业务需要)
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注