我目前处于一个基于问题 /答案的相当大的应用程序中(类似stackoverflow / andownbag.com),我们正在使用sql(azure)和nhibernate进行数据访问,并用于UI应用程序。

到目前为止,架构大致沿着Stackoverflow db的线条大致沿着我们有一个单一的意义 邮政 表(包含两个问题 /答案)

可能会按照以下存储库接口的线路使用:

public interface IPostRepository
{
    void PutPost(Post post);
    void PutPosts(IEnumerable<Post> posts);

    void ChangePostStatus(string postID, PostStatus status);

    void DeleteArtefact(string postId, string artefactKey);
    void AddArtefact(string postId, string artefactKey);

    void AddTag(string postId, string tagValue);
    void RemoveTag(string postId, string tagValue);

    void MarkPostAsAccepted(string id);
    void UnmarkPostAsAccepted(string id);

    IQueryable<Post> FindAll();
    IQueryable<Post> FindPostsByStatus(PostStatus postStatus);
    IQueryable<Post> FindPostsByPostType(PostType postType);
    IQueryable<Post> FindPostsByStatusAndPostType(PostStatus postStatus, PostType postType);
    IQueryable<Post> FindPostsByNumberOfReplies(int numberOfReplies);
    IQueryable<Post> FindPostsByTag(string tag);
}

我的问题是:我在哪里 /如何将Solr适合此“帖子”(我将使用Solrnet进行与Solr的实际通信)更好地查询。

理想情况下,我将使用SQL DB作为一个持久的商店 - 上述可视化操作的大部分将进入某种Solrfinder类(或类似的东西)

身体属性是引起当前问题的属性 - 它相当大,并减慢了SQL上的查询。

我的主要问题是,例如,如果某人“更新”帖子 - 例如,添加一个新标签,那么整个帖子将需要重新索引。显然,这样做需要这样的查询:

“从帖子中选择 * where id = xyz”

当然,这将非常慢。 Solrnet有一个NHIBERNATE设施 - 但我相信这将与上述结果相同吗?

我想到了这一方法,我希望您的观点:

  • 将ID添加到队列(Amazon SQS之类的东西 - 我喜欢与此使用的易用性)
  • 在某个地方拥有上述查询,构建文档并将其重新添加到Solr的地方(或一堆服务)。

我设计的另一个问题:“重新索引”方法应该从哪里调用? MVC控制器?还是我应该有一个“后服务”类型类,它包含iPostrepository的实例?

任何指针都会在这一指针中得到很多收到!

有帮助吗?

解决方案

在我工作的电子商务网站上,我们使用Solr提供快速的产品目录和搜索产品目录。 (用非solr怪胎术语,这意味着“ ATI卡(34),Nvidia(23),Intel(5)”风格的导航链接,您可以用来通过Zappos,Amazon,Amazon,Amazon,Amazon,Amazon,Amazon,Amazon,Amazon,Amazon,Amazon,Amazon,Amazon,Amazon,Amazon,Amazon上的产品目录进行钻探的“导航链接”。 Newegg和Lowe。)

这是因为Solr旨在快速,很好地做此类事情,并且在传统的关系数据库中尝试有效地做这种事情是,除非您想开始在该公司上添加和删除索引,否则不会发生这种事情飞翔并全力以赴,这只是 咳嗽 Magento 咳嗽 愚蠢的。因此,我们的SQL Server数据库是“权威”数据存储,Solr索引是该数据的“只有“投影”。

到目前为止,您和我在一起,因为听起来您处在类似的情况下。下一步是确定SOLR索引中的数据是否可以稍微陈旧。您可能已经接受了一个事实,即它会有些陈旧,但是接下来的决定是

  • 太过时了吗?
  • 我何时将速度或查询功能评估而不是稳定性?

例如,我有我所谓的“工人”,这是一个使用的Windows服务 Quartz.net 执行C# IJob 定期实施。每3小时,执行这些工作之一是 RefreshSolrIndexesJob, ,所有工作所做的就是ping HttpWebRequesthttp://solr.example.com/dataimport?command=full-import. 。这是因为我们使用Solr的内置 DataImporthandler 实际上从SQL数据库中吸收数据;这项工作只需要定期“触摸”该URL才能使同步工作。由于DataImporthandler定期进行更改,因此这一切都在后台有效地运行,对网站的用户透明。

这确实意味着产品目录中的信息最多可能是3小时的陈旧。用户可以单击“目录”页面上“库存中的媒体(3)”的链接(由于查询SOLR是通过查询Solr生成的这种刻面数据),但是在产品详细信息页面上查看没有媒体(因为在此上,页面,数量信息是几件事之一 不是 被缓存和查询直接针对数据库)。这很烦人,但在我们特别的情况下通常很少见(我们是一家相当小的企业,而不是 流量很大),无论如何,当我们再次从头开始重建整个索引时,它将在3个小时内修复,因此我们接受了这一点作为合理的权衡。

如果您可以接受这种“稳定性”,那么这个背景工作过程是一个好方法。您可以采用“每隔几个小时重建整个过程”的方法,或者您的存储库可以将ID插入桌子中,例如 dbo.IdentitiesOfStuffThatNeedsUpdatingInSolr, ,然后一个背景过程可以定期扫描该表,并仅在Solr中更新这些文档,如果从头开始重建整个索引,鉴于数据集的大小或复杂性是不合理的。

第三种方法是让您的存储库产生一个背景线程,该线程会或多或少地更新有关当前文档的SOLR索引,因此数据仅持续几秒钟:

class MyRepository
{
    void Save(Post post)
    {
         // the following method runs on the current thread
         SaveThePostInTheSqlDatabaseSynchronously(post);

         // the following method spawns a new thread, task,
         // queueuserworkitem, whatevever floats our boat this week,
         // and so returns immediately
         UpdateTheDocumentInTheSolrIndexAsynchronously(post);
    }
}

但是,如果出于某种原因爆发,您可能会错过Solr中的更新,因此,让Solr定期进行“全部吹牛并刷新”,或者拥有Reaper Background Worker-Type服务,这仍然是一个好主意。 Solr中的所有人曾经在蓝色月亮中曾经有一个数据。

至于从Solr查询这些数据,您可以采用一些方法。一种是隐藏索尔完全通过存储库的方法存在的事实。我个人不建议这样做,因为您的SOLR模式的机会将无耻地量身定制为UI,这将访问该数据。我们已经决定使用Solr提供简单的信息,分类和快速显示信息,因此我们不妨在最大程度上使用它。这意味着当我们打算访问SOLR时,并且是指我们访问最新的,非接近的数据库对象时,将其显式在代码中。

就我而 ItemGroup, ,使用其定价规则,然后将其保存回去),放弃了存储库模式,因为当Nhibernate及其映射已经在将数据库抽象时,我通常不会看到其值。 (这是个人选择。)

但是,当查询数据时,我很了解是否将其用于目录的目的(我关心 速度查询)或用于在后端管理应用程序上的表中显示(我关心 货币)。对于网站上的查询,我有一个界面称为 ICatalogSearchQuery. 。它有一个 Search() 接受 SearchRequest 在哪里定义了一些参数 - 选择的方面,搜索词,页码,每个页面的项目数等 SearchResult- 示例方面,结果数,此页面上的结果等。非常无聊的东西。

有趣的是,实施 ICatalogSearchQuery 正在使用列表 ICatalogSearchStrategy在下面。默认策略, SolrCatalogSearchStrategy, ,直接通过普通的老式击中Solr HttpWebRequest 并在 HttpWebResponse (恕我直言,它比某些Solr客户库库更容易使用,尽管自从我上次看它们以来,它们可能会变得更好)。如果该策略出于某种原因引发异常或呕吐,那么 DatabaseCatalogSearchStrategy 直接列入SQL数据库 - 尽管它忽略了某些参数 SearchRequest, ,例如FaceTing或“高级文本搜索”,因为这是在那里效率低下的,这是我们首先使用Solr的全部原因。这个想法是,通常Solr以全功能的荣耀快速回答我的搜索请求,但是如果某些东西炸毁并且Solr崩溃了,那么网站的目录页面仍然可以通过使用“降低功能性功能模式”来发挥作用。有限的功能集。 (由于我们已经在代码中明确说明这是一个搜索,因此该策略可以自由地忽略某些搜索参数,而不必担心过于严重影响客户。

关键要点: 重要的是,对可能刻板的数据存储进行查询的决定与权威数据存储已经进行了 显式- 如果我想要具有高级搜索功能的快速,可能陈旧的数据,我会使用 ICatalogSearchQuery. 。如果我想要具有插入/update/delete功能的慢速,最新数据,我会使用nhibernate的命名查询(或您的情况下的存储库)。而且,如果我在SQL数据库中进行了更改,我知道最终将最终更新Solr,从而最终使事情保持一致。 (如果有什么真正重要的事情,我可以直接播放一个活动或直接ping solr商店,告诉它进行更新,如果需要的话,可能在背景线程中。)

希望能给您一些见识。

其他提示

我们使用Solr查询大型产品数据库。大约100万种产品和30家商店。

我们所做的是在产品表上使用触发器,并在SQL Server上使用库存表。

每次更改一行时,都会标记要重新索引的产品。而且我们有一个Windows服务,可以抓住这些产品并将其发布给每10秒钟。 (每批限制100种产品)。

这是超级高效的,几乎是实时的股票信息。

如果您有一个很大的文本字段(您的“身体”字段),则是,在后台重新索引。您提到的解决方案(队列或定期背景服务)将做到。

MVC控制器应忽略此过程。

我注意到您的存储库界面中有iQueryables。 Solrnet当前不 有一个LINQ提供商. 。无论如何,如果这些操作是您要与solr一起做的(即没有柜子),则可能需要考虑使用lucene.net,哪个 有一个LINQ提供商。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top