2017-03-02 57 views
1

我基本上试图模仿ES中的连接,并且我知道这对于ES来说并不是一个很好的用例,但同时我所要完成的并不是对于搜索功能而言似乎不寻常。我已经阅读了ES文档,博客文章,绘制图表,当然还在本地测试了不同的场景,但是我仍然很难围绕如何为ES索引这些数据。这是我第一个ES项目,也是我第一次真正与noSQL类型的环境交互。如何为Elasticsearch索引这些数据

想象一个社会配方站点(为简单起见)...

用户可以张贴原来的食谱。其他用户可以“喜欢”(一次),“保存至”(多次保存至不同类别)和“烹饪”(可以多次烹饪食谱)食谱。

用户可以在不同的简单标志上搜索食谱并对其进行过滤,例如“食谱至少煮过一次”以及他们是否喜欢,保存和/或烹饪食谱。此外,当您查看用户的个人资料时,您可以搜索他们喜欢,保存和烹饪的食谱。以及用户创建的食谱。

目前的设置工作,但似乎不可扩展,是一个配方的索引,其各种是/否标志,以及每个字段的一个字段用于likes_by_users,saved_by_users和cooked_by_users。这些字段包含一组user_id,这些user_id在配方中执行了任何这些操作。然后,当我想要过滤时,我传递user_id(或user_id,例如,如果您想查看您的朋友烹饪过的东西),并筛选结果是否显示在相关数组中。但是,如果最终可能有数百万次这样的交互,那么这种存储和搜索似乎并不是很好。我还可以存储在用户的配方IDS但最终,好像我最终会得到一个类似的问题,我会需要首先从用户查询这些ID的额外的麻烦。

我一直在尝试和/或思考:

  1. 进行非标准化的一切。我认为这是首选的ES方式,但我担心这只是如此重复的数据(可以搜索配方标题,内容,类别等),并且其中一些频繁变化。例如,如果用户喜欢配方,则会更新该配方的喜欢计数,以便可以按类似计数对结果进行排序。

我相信这将需要创建一个配方的副本,永远与它进行交互的用户,然后在那里存储交互。因此,喜欢的标志,以及它保存的类别的数据数组以及已经烹饪的时间数据数组。我相信我仍然需要在user_ids筛选上,如果有人被任何过滤他们的朋友已经煮熟的数组来传递,但我不认为用户将有上百万的朋友,可能是200下仍然太许多ID传入?将太多的数据保存到太多的数据?此外,有些字段可能会经常更新,这使得这种声音更加糟糕。

  1. 用户下的嵌套食谱也听起来不正确,因为当更新其他东西时,一切都需要重新索引。

  2. 在文档,父/子听起来像是不得已的选择,也是不健全的安静适合这种使用情况。

  3. 我已经考虑过拉动ID来从MySQL过滤的(即配方ID的用户具有与相互作用)并传递到那些ES。然而,一个,mySQL只能连接这么多的id(并且类似地,如果将它们构建为代码中的字符串,如果它们对于mySQL来说太长是明智的),以及两个,我不确定这是否是一个有效的方法来过滤ES结果(太多的数据)。

我已经尝试了一些其他的东西,如单独用户建立索引和配方之间的关系,但一切似乎只是回落到疯狂的小镇。

我也不知道ES有多少钱。阅读文档时,会提到“如果你有很多XYZ,这不是一个好主意”,但我不知道在这些情况下有多少手段。我阅读的唯一具体部分是关于更新非规范化博客文章中的用户名称,并且更新“几千条”需要不到一秒的时间。有没有什么经验法则可以用来估计对于存储在字段中的数据,传递给过滤器的数据或文档进行更新等事情有多大?

回答

0

由于实体(用户,食谱,类别等)以各种方式链接在一起,并且在没有竞争条件的情况下以高吞吐量更新这些数据并不是微不足道的,所以在Elasticsearch上实现相当棘手。

是否在用户之间共享类别?我的意思是,当一个配方保存到一个类别(如标签)时,这个信息是否对每个人都可见?如果是这样,这个结构应该让你开始。

听起来像你应该有两种类型的文件:食谱和烹饪行动/用户/食谱。

配方结构:

{ 
    "_id": "rga9gia0934gau90" (could be auto-generated by ES) 
    "created_by": 123   (user id) 
    "contents": "Pour x grams of sugar..." 
    "ingredients": ["sugar", "..."], 
    "tags": ["unhealthy", "sweet", "..."] 
} 

烹饪日期结构:

{ 
    "_id": "123-rga9gia0934gau90" (generated as {user_id}-{recipe-id}) 
    "user_id": 123, 
    "recipe_id": "rga9gia0934gau90", 
    "cooked_at_dates": ["2017-01-02", "2017-01-07"], 
    "cooked_n_times": 2 
} 

这样,大多数的更新是本地的一个文件。然而,诸如“甜食谱用户X尚未煮熟”之类的一些查询需要两个ES查询:首先获得用户烹饪的所有食谱的食谱ID,并且第二查询找到没有任何食谱的所有甜食谱列出的ID。这不会扩展到数以万计的食谱,但应该可以正常工作数百或数千。

+0

谢谢!可悲的是,类别是个人收藏和用户特定的。 也很伤心,这是在几十万(HoT)的范围内,所以我可能不得不与2个查询一起去。有助于知道这是正确的轨道。 如果我可能会问,澄清,如果过滤的配方ID是在数百,是否可以传递给结果HoT的搜索?但是传递一个HoT ID的过滤器会很糟糕?或者都不好?例如。搜索500K文档查找“坚果”,并传递用户烹饪的200个ID。 – Pango

+0

嗯,基本上产生过大的查询将有不佳的表现。但是你应该对它进行基准测试,看看过滤器上的10k与1k ids差距有多大。如果类别是用户特定的,那么您将不得不将它们分开存储为与我的示例中的烹饪日期类似的结构。 – NikoNyrh

+0

或者实际上您可以将标签存储到与烹饪时间相同的文档中。但ES不建议用作数据库,您应该将此信息存储在某个“安全”的地方,以防需要将其重新索引到ES。 – NikoNyrh