【问题标题】:Search efficiently for records matching given set of properties/attributes and their values (exact match, less than, greater than)有效搜索与给定属性/属性集及其值匹配的记录(精确匹配、小于、大于)
【发布时间】:2015-03-05 20:10:27
【问题描述】:

这是一个相当简单的问题描述。但是,我无法提出任何合理的解决方案,因此解决方案可能会也可能不会那么容易解决。问题来了:

假设有许多记录描述一些对象。例如:

{
  id         : 1,
  kind       : cat,
  weight     : 25 lb,
  color      : red
  age        : 10,
  fluffiness : 98 
  attitude   : grumpy
}

{
  id       : 2,
  kind     : robot,
  chassis  : aluminum,
  year     : 2015,
  hardware : intel curie,
  battery  : 5000,
  bat-life : 168,
  weight   : 0.5 lb,
}

{
  id       : 3,
  kind     : lightsaber,
  color    : red,
  type     : single blade,
  power    : 1000,
  weight   : 25 lb,
  creator  : Darth Vader
}

属性不是预先指定的,因此可以使用任何属性值对来描述对象。 如果有 1 000 000 个记录/对象,则很容易有 100 000 个不同的属性。

我的目标是有效地搜索包含所有记录的数据结构,并在可能的情况下(快速)找到与给定条件匹配的记录。

例如,搜索查询可以是:Find all cats that weigh more than 20 and are older than 9 and are more fluffy than 98 and are red and whose attitude is "grumpy".

我们可以假设可能有无限数量的记录和无限数量的属性,但任何搜索查询包含不超过 20 个数字 (lt,gt) 子句。

我能想到的一种使用 SQL/MySQL 的可能实现是使用全文索引。

例如,我可以将非数字属性存储为“kind_cat color_red aspect_grumpy”,通过它们搜索以缩小结果集,然后扫描包含数字属性的表以查找匹配项。然而,似乎(我目前不确定)gt, lt 搜索通常使用这种策略可能代价高昂(我必须为 N 个数字子句做至少 N 个连接)。

我想到了 MongoDB 思考这个问题,但是虽然 MongoDB 自然允许我存储键值对,但是通过某些字段(不是全部)搜索意味着我必须创建包含所有可能的顺序/排列中的所有键的索引(这是不可能的)。

这是否可以使用 MySQL 或任何其他 dbms 有效地完成(可能在对数时间内??)? - 如果没有,是否有数据结构(可能是一些多维树?)和算法可以有效地大规模执行这种搜索(考虑时间和空间复杂度)?

如果无法解决以这种方式定义的问题,是否有任何启发式方法可以在不牺牲太多的情况下解决它。

【问题讨论】:

    标签: sql database algorithm data-structures complexity-theory


    【解决方案1】:

    如果我猜对了,你的想法是这样的:

    create table t 
    ( id int not null
    , kind varchar(...) not null
    , key varchar(...) not null
    , val varchar(...) not null
    , primary key (id, kind, key) );
    

    这种方法存在几个问题,您可以通过谷歌搜索 EAV 以了解更多信息。一个例子是在进行比较时必须将 val 转换为适当的类型('2' > '10')

    也就是说,像这样的索引:

    create unique index ix1 on t (kind, key, val, id)
    

    会稍微减轻您将遭受的痛苦,但设计不会很好地扩展,并且具有 1E6 行和 1E5 属性,性能将远非良好。您的示例查询如下所示:

    select a.id
    from ( select id 
           from ( select id, val 
                  from t 
                  where kind = 'cat'
                    and key = 'weight' 
                )
           where cast(val as int) > 20
         ) as a
    join ( select id 
           from ( select id, val 
                  from t 
                  where kind = 'cat'
                    and key = 'age' 
                )
           where cast(val as int) > 9
         ) as b
         on a.id = b.id
    join ( ...
                    and key = 'fluffy' 
                )
           where cast(val as int) > 98
         ) as c
         on a.id = c.id
    join ...
    

    【讨论】:

    • 是的,它不能很好地扩展,你的 sql sn-p 正好说明了我的想法。事实上,我不希望具体的例子/概念证明作为答案,而是可以扩展的通用解决方案(概念本身)。不过,感谢您的时间和回答。
    猜你喜欢
    • 2015-09-16
    • 2015-12-23
    • 1970-01-01
    • 1970-01-01
    • 2017-01-09
    • 2020-03-06
    • 2015-08-02
    • 2014-12-03
    • 1970-01-01
    相关资源
    最近更新 更多