如何在域驱动设计之后对堆栈溢出等网站的搜索上下文进行建模?
让我们说在我的域名中,我有三种类型的实体,如问题,答案,问题标签。 我必须以接受搜索字符串并返回匹配的问题,答案和标签的方式对搜索上下文进行建模。
我想明白,在搜索环境中,搜索只是一个执行搜索的ddd服务,或者可能存在一些实体,聚合等。
可以假设匹配算法是简单的sql,如查询。
答案 0 :(得分:1)
您需要在查询服务中实现搜索。
CQRS非常适合DDD,因为当您想要更新模型时,您可以使用命令,例如在您的情况下:
AnswerToQuestionCommand,PostNewQuestionCommand等
这些命令被发送到您的应用程序服务,该服务更新实体,实体又发送一个DomainEvent,它在六边形体系结构中被拦截并更新搜索索引。您可以在六边形体系结构中执行此操作:通过调用专用于在同一事务中维护索引的服务。如果索引也已更新,您认为实体是持久的。我会这样走。
以下是Spring @TransactionalEventListener
的示例@Component
public class ProjectRenamedListener {
@Value("${spring.jpa.properties.hibernate.search.default.indexBase:target}")
private String indexBase;
private final Logger logger = LoggerFactory.getLogger(ProjectRenamedListener.class);
@TransactionalEventListener
public void projectRenamed(final ProjectRenamed event) {
try (final StandardAnalyzer analyzer = new StandardAnalyzer();
final Directory directory = NIOFSDirectory.open(Paths.get(indexBase, ProjectData.class.getName()));
final IndexWriter writer = new IndexWriter(directory, new IndexWriterConfig(analyzer))){
final Document document = new Document();
document.add(new StringField("project_id", event.projectId().identity(), Field.Store.YES));
document.add(new StringField("tenant_id", event.tenant().identity(), Field.Store.YES));
document.add(new TextField("name", event.name(), Field.Store.YES));
writer.updateDocument(new Term("project_id", event.projectId().identity()), document);
} catch (IOException e) {
logger.warn("Unable to update index for project name.", e.getMessage());
}
}
}
当您需要查询问题,答案等时,您将通过查询服务。您询问索引,并加载要返回给客户端的实体。
这样做的好处是,当您修改它并查询它时,它不必是同一个对象。当你开始时,由于代码重复,听起来有点奇怪,但从长远来看,它显然是优秀的解决方案,因为在读取/查询操作之间没有耦合,这种操作发生了很多并且应该很快,并且写入操作不应该发生很多并且必须特别超快。
我会建议Vaughn Vernon在查询服务上的方法(https://github.com/VaughnVernon/IDDD_Samples),我使用lucene作为查询服务,这里有一些代码:
@PreAuthorize("hasAuthority('Administrator')")
public Page<ProjectData> searchProjectsData(
final String tenantId,
final String queryText,
final Pageable pageable) {
if (!StringUtils.isEmpty(tenantId)) {
return this.searchProjectsDataOfTenant(tenantId, queryText, pageable);
}
final StandardAnalyzer analyzer = new StandardAnalyzer();
final QueryBuilder builder = new QueryBuilder(analyzer);
final Query query = builder.createPhraseQuery("name", queryText);
try {
final IndexReader reader = DirectoryReader.openIfChanged(this.directoryReader);
final IndexSearcher searcher = new IndexSearcher(reader);
final TopDocs documents = searcher.search(query, pageable.getPageSize());
return this.fetchProjectsData(searcher, documents, pageable);
} catch (IOException e) {
throw new RuntimeException(String.format("Unable to search project for query: %s", queryText), e);
}
}
答案 1 :(得分:0)
对于搜索有界的上下文,你可能不需要整套DDD战术模式,没有。除非您计划存储搜索偏好或创建搜索模板,否则 - 即使这样,它似乎非常CRUD。
但是,设计搜索上下文如何索引或访问来自其他BC的数据可能是一个更复杂的问题。