欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 文化 > 这是啥设计模式-组合模式

这是啥设计模式-组合模式

2024/10/24 5:23:45 来源:https://blog.csdn.net/he_wen_jie/article/details/141301823  浏览:    关键词:这是啥设计模式-组合模式

召回链路一般都是使用多路召回,例如文本召回,向量召回,KV召回等等。

1. 面向接口编程,而非实现

还是那句话,客户端并怎么不关心召回策略的具体实现,他只关心接口。通过这个接口它可以得到自己想要的召回结果。

class Recall {
public:explicit Recall(const std::string& name) : m_name(name) {}virtual ~Recall() = default;virtual void recall(int depth) const = 0;
private:std::string m_name;
};

我们定义一个召回策略的接口,后续所有策略都继承这个接口,其中m_name是策略的名称,recall是召回函数。

2. 实现接口

// 文本召回
class InvertRecall : public Recall {
public:explicit InvertRecall(const std::string& name) : Recall(name) {}void recall(int depth) const override {std::cout << std::string(depth, ' ') << "-" << name << std::endl;}
};// 向量召回
class VectorRecall : public Recall {
public:explicit VectorRecall(const std::string& name) : Recall(name) {}void recall(int depth) const override {std::cout << std::string(depth, ' ') << "-" << name << std::endl;}
};// KV召回
class KvRecall : public Recall {
public:explicit KvRecall(const std::string& name) : Recall(name) {}void recall(int depth) const override {std::cout << std::string(depth, ' ') << "-" << name << std::endl;}
};

3. 客户端调用

客户端调用也非常的方便,只要调用出自己想要的召回策略即可

Recall invertRecall = new InvertRecall("invert");
Recall vectorRecall = new VectorRecall("vector");
Recall kvRecall = new KvRecall("kv");invertRecall->recall(0);
vectorRecall->recall(0);
kvRecall->recall(0);

增加一些策略

每一个召回策略都可以往下细分,例如向量召回又有FM召回和DSSM召回,FM召回呢又衍生了AFM和FFM,KV召回具体又有I2I召回,I2I召回又衍生了Item2vec和swingI2I算法等等。
我们之前所说的向量召回,文本召回,KV召回都是大类,这里面包含了更细粒度的分类和实现方法。

// 向量召回策略
Recall dssmRecall = new DSSMRecall("dssm");
Recall afmRecall = new AFMRecall("afm");
Recall ffmRecall = new FFMRecall("ffm");
// KV召回测录
Recall swingRecall = new SwingRecall("swing");
Recall item2vecRecall = new Item2VecRecall("item2vec");// 倒排召回
Recall boolRecall = new BoolRecall("bool");dssmRecall->recall(0);
afmRecall->recall(0);
ffmRecall->recall(0);
swingRecall->recall(0);
item2vecRecall->recall(0);
boolRecall->recall(0);

客户端需要调用所有的召回策略,每次新增都需要调用新的召回策略算法的recall方法。

5. 多态分组调用

一种极其简单的方法是增加一个数组,这可是多态常用的一种方法。

std::vector<Recall*> strategys{dssmRecall, afmRecall, ffmRecall, swingRecall, item2vecRecall, boolRecall};for(auto strategy: strategys) {strategy->recall(0);
}

如果你愿意更进一步的话,还可以对这些召回策略进行分组,例如分为向量召回,文本召回,kv召回三个组,这样会更加清晰,想要增加什么哪个类的策略就放到哪个数组里即可

std::vector<Recall*> vectorStrategys{dssmRecall, afmRecall, ffmRecall};
std::vector<Recall*> invertStrategys{boolRecall};
std::vector<Recall*> kvStrategys{swingRecall, item2vecRecall};
for(auto strategy: vectorStrategys) {strategy->recall(0);
}
for(auto strategy: invertStrategys) {strategy->recall(0);
}
for(auto strategy: kvStrategys) {strategy->recall(0);
}

对客户端调用来说也更加清晰了。

6. 组合模式

用组合模式对上面进行进一步优化

// 召回接口
class Recall {
public:explicit Recall(const std::string& name) : m_name(name) {}virtual ~Recall() = default;virtual add(Recall* recall) {}virtual void recall(int depth) const = 0;
private:std::string m_name;
};// 召回策略组
class RecallGroup : public Recall {
private:std::vector<Recall*> children;
public:explicit RecallGroup(const std::string& name) : RecallGroup(name) {}void add(Recall* recall) {children.push_back(recall);}void recall(int depth) const override {std::cout << std::string(depth, ' ') << "+" << name << std::endl;for (auto& child : children) {child->recall(depth + 4);}}
};

客户端调用

// 向量召回策略
Recall vectorGroup = new RecallGroup("vector");
Recall dssmRecall = new DSSMRecall("dssm");
vectorGroup.add(dssmRecall);
Recall fmGroup = new RecallGroup("fm");
Recall afmRecall = new AFMRecall("afm");
Recall ffmRecall = new FFMRecall("ffm");
fmGroup.add(afmRecall);
fmGroup.add(ffmRecall);
vectorGroup.add(fmGroup);// KV召回测录
Recall kvGroup = new RecallGroup("kv");
Recall swingRecall = new SwingRecall("swing");
Recall item2vecRecall = new Item2VecRecall("item2vec");
kvGroup.add(swingRecall);
kvGroup.add(item2vecRecall);
// 倒排召回
Recall invertGroup = new RecallGroup("vector");
Recall boolRecall = new BoolRecall("bool");
invertGroup.add(boolRecall);// 淘宝召回
Recall tbaoGroup = new RecallGroup("taobao");
tbaoGroup.add(vectorGroup);
tbaoGroup.add(kvGroup);
tbaoGroup.add(invertGroup);for(auto task : tbaoGroup) {task->recall(0);
}// 天猫召回
Recall tmaoGroup = new RecallGroup("taobao");
taobaoGroup.add(vectorGroup);for(auto task : tmaoGroup) {task->recall(0);
}// 闲鱼召回
Recall xianyuGroup = new RecallGroup("taobao");
xianyuGroup.add(swingRecall);
xianyuGroup.add(fmGroup);
for(auto task : xianyuGroup) {task->recall(0);
}

对于客户端来说,他只需要关注自己想要调用的策略即可,可以是单个策略,也可以是某一个策略组,更加的灵活了

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com