用于查找“朋友发布的帖子”的 Amazon SimpleDB 查询

发布于 2024-09-13 06:55:41 字数 445 浏览 6 评论 0原文

我一直在开发一个 iPhone 应用程序,该应用程序查询中继我存储在 Amazon SimpleDB 中的数据的服务器。我有一个由不同用户的“提交”的数据库表。我正在与 Facebook 进行交互以检索 Facebook 好友,并希望对“提交”进行查询以查找好友的帖子 - 例如:(

SELECT * FROM submissions WHERE userID = '00123' OR userID = '00124' OR .... 

通过完整的好友列表)

我认为使用这种 select 语句会遇到 Amazon 查询限制-

[每个 Select 表达式的最大比较次数:20]

你能想出一种方法来使用 SimpleDB 优雅地实现这一点吗? 我不想做一堆 20 人的查询。 或者,我是否需要转移到不同的数据库包,然后进行跨表查询?

谢谢!

I have been developing an iPhone app which queries a server that relays data I store in Amazon SimpleDB. I have a database table of "Submissions" by various users. I am interfacing with Facebook to retrieve Facebook Friends and wish to make a query to "Submissions" to find posts by friends - like:

SELECT * FROM submissions WHERE userID = '00123' OR userID = '00124' OR .... 

(through complete list of friends)

I think this will run into an Amazon query limit with this kind of select statement -

[Maximum number of comparisons per Select expression: 20]

Can you think of a way to elegantly pull this off with SimpleDB?
I'd rather not have to do a bunch of 20 person queries.
Or, do I need to move to a different database package and then do cross-table queries?

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

万人眼中万个我 2024-09-20 06:55:41

有一种方法可以使用 SimpleDB 来做到这一点,但它并不优雅,它更像是一种 hack,因为它要求您在提交项中人为地复制 userid 属性。

它基于这样一个事实:尽管每个 IN 谓词只能进行 20 次比较,但您可以拥有 20 个 IN 谓词如果它们各自命名不同的属性。因此,请向表单的提交项目添加其他综合属性:

userID='00123' userID_2='00123' userID_3='00123' userID_4='00123' ... userID_20='00123'

对于给定的它们都具有相同的值提交。然后,您可以通过单个查询获取最多 400 个朋友的提交:

SELECT * FROM submissions 
WHERE userID IN('00120','00121',...,'00139') OR
    `userID_2` IN('00140','00141',...,'00159') OR
    `userID_3` IN('00160','00161',...,'00179') OR
    `userID_4` IN('00180','00181',...,'00199') OR
    ...
    `userID_20` IN('00300','00301',...,'00319')

您可以在创建提交时填充 19 个额外属性(如果您有备用属性),这听起来不像提交的用户会这样做永远改变。此外,您可能希望显式命名要返回的属性(而不是使用 * ),因为现在返回数据集中有 19 个您不关心的属性。

从数据模型的角度来看,这显然是一种黑客攻击。但话虽如此,对于拥有 400 名或更少朋友的用户来说,它确实为您提供了您想要的东西:单个查询,以便您可以按日期或其他条件进行限制、按最近排序、翻阅结果等。不幸的是,容量400 的好友列表无法容纳所有 Facebook 用户的好友列表。因此,您可能仍然需要为大型好友列表实施多查询解决方案。

我的建议是,如果 SimpleDB 满足您的应用程序的需求(除了这个问题),那么请考虑使用 hack。但如果您需要重复执行此类操作,那么 SimpleDB 可能不是最佳选择。

There is a way to do it with SimpleDB but it isn't elegant, it's more of a hack since it requires you to artificially duplicate the userid attribute in your submission items.

It's based on the fact that although you can only have 20 comparisons per IN predicate, you can have 20 IN predicates if they each name different attributes. So add additional synthetic attributes to your submission items of the form:

userID='00123' userID_2='00123' userID_3='00123' userID_4='00123' ... userID_20='00123'

They all have the identical value for a given submission. Then you can fetch the submission of up to 400 friends with a single query:

SELECT * FROM submissions 
WHERE userID IN('00120','00121',...,'00139') OR
    `userID_2` IN('00140','00141',...,'00159') OR
    `userID_3` IN('00160','00161',...,'00179') OR
    `userID_4` IN('00180','00181',...,'00199') OR
    ...
    `userID_20` IN('00300','00301',...,'00319')

You can populate the 19 extra attributes at the time the submission is created (if you have the attributes to spare) and it doesn't sound like a submission's user would ever change. Also you may want to explicitly name the attributes to be returned (instead of using * ) since you would now have 19 of them that you don't care about in the return data set.

From the data model point of view, this is clearly a hack. But having said that, it gives you exactly what you would want, for users with 400 friends or less: a single query so you can restrict by date or other criteria, sort by most recent, page through results, etc. Unfortunately, a capacity of 400 won't accommodate the friend lists of all facebook users. So you may still need to implement a multi-query solution for large friend lists just the same.

My suggestion is that if SimpleDB suits the needs of your app with the exception of this issue, then consider using the hack. But if you need to do things like this repeatedly then SimpleDB is probably not the best choice.

尘世孤行 2024-09-20 06:55:41

您需要 IN 子句或连接到临时表。不幸的是 AmazonSimpleDB 有其局限性。正是出于这个原因,我们放弃了它,而选择了一个很有前途的项目。在我们切换方向之前,我们走的是多线程之路并使用 NextToken 功能。

您可以对 SimpleDB 执行并行(多线程)查询来获取提交,每个查询最多查找 20 个用户 ID,然后将结果合并到一个列表中。不过,也许是时候考虑切换到 MySQL 或 SQL Server,以便能够将 ID 列表作为临时表上传,然后执行简单的联接来获取结果。

You're needing either an IN clause or a join to a temp table. Unfortunately AmazonSimpleDB has its limitations. We abandoned it on a promising project for this very reason. We went down the path of multithreading and using the NextToken functionality before we switched gears.

You could execute parallel (multithreaded) queries to SimpleDB to get submissions, each query looking for up to 20 user IDs and then merging the results into one list. Still, it's probably time to consider a switch to MySQL or SQL Server to be able to upload a list of IDs as a temp table and then do a simple join to get the results.

稚然 2024-09-20 06:55:41

我为 SimpleDB 创建了 Simple Savant .NET 库,并且我碰巧有一些用于拆分的实用程序代码并行运行多个选择查询,同时将每个选择的 IN 子句限制为 20 个值。我可能会将这段代码放入下一个 Savant 版本中,但这里是为任何发现它有用的人准备的:

    /// <summary>
    /// Invokes select queries that use parameter lists (with IN clauses) by splitting the parameter list
    /// across multiple invocations that are invoked in parallel.
    /// </summary>
    /// <typeparam name="T">The item type</typeparam>
    /// <typeparam name="P">The select parameter type</typeparam>
    /// <param name="savant">The savant instance.</param>
    /// <param name="command">The command.</param>
    /// <param name="paramValues">The param values.</param>
    /// <param name="paramName">Name of the param.</param>
    /// <returns></returns>
    public static List<T> SelectWithList<T,P>(ISimpleSavantU savant, SelectCommand<T> command, List<P> paramValues, string paramName)
    {
        var allValues = SelectAttributesWithList(savant, command, paramValues, paramName);
        var typedValues = new List<T>();
        foreach (var values in allValues)
        {
            typedValues.Add((T)PropertyValues.CreateItem(typeof (T), values));
        }
        return typedValues;
    }

    /// <summary>
    /// Invokes select queries that use parameter lists (with IN clauses) by splitting the parameter list
    /// across multiple invocations that are invoked in parallel.
    /// </summary>
    /// <typeparam name="P">The select parameter type</typeparam>
    /// <param name="savant">The savant instance.</param>
    /// <param name="command">The command.</param>
    /// <param name="paramValues">The param values.</param>
    /// <param name="paramName">Name of the param.</param>
    /// <returns></returns>
    public static List<PropertyValues> SelectAttributesWithList<P>(ISimpleSavantU savant, SelectCommand command, List<P> paramValues, string paramName)
    {
        Arg.CheckNull("savant", savant);
        Arg.CheckNull("command", command);
        Arg.CheckNull("paramValues", paramValues);
        Arg.CheckNullOrEmpty("paramName", paramName);

        var allValues = new List<PropertyValues>();
        if (paramValues.Count == 0)
        {
            return allValues;
        }

        var results = new List<IAsyncResult>();
        do
        {
            var currentParams = paramValues.Skip(results.Count * MaxValueTestsPerSimpleDbQuery).Take(MaxValueTestsPerSimpleDbQuery).ToList();
            if (!currentParams.Any())
            {
                break;
            }
            var currentCommand = Clone(command);
            currentCommand.Reset();
            var parameter = currentCommand.GetParameter(paramName);
            parameter.Values.Clear();
            parameter.Values.AddRange(currentParams.Select(e => (object)e));
            var result = savant.BeginSelectAttributes(currentCommand, null, null);
            results.Add(result);
        } while (true);

        foreach (var result in results)
        {
            var values = ((ISimpleSavant2)savant).EndSelectAttributes(result);
            allValues.AddRange(values);
        }

        return allValues;
    }

    private static SelectCommand Clone(SelectCommand command)
    {
        var newParameters = new List<CommandParameter>();
        foreach (var parameter in command.Parameters)
        {
            var newParameter = new CommandParameter(parameter.Name, parameter.PropertyName, null);
            newParameter.Values.Clear();
            newParameters.Add(newParameter);
        }
        var newCommand = new SelectCommand(command.Mapping, command.CommandText, newParameters.ToArray())
            {
                MaxResultPages = command.MaxResultPages
            };
        return newCommand;
    }

I created the Simple Savant .NET library for SimpleDB, and I happen to have some utility code lying around for splitting and running in parallel multiple select queries, while limiting the IN clause of each select to 20 values. I'll probably roll this code into the next Savant release, but here it is for anyone who finds it useful:

    /// <summary>
    /// Invokes select queries that use parameter lists (with IN clauses) by splitting the parameter list
    /// across multiple invocations that are invoked in parallel.
    /// </summary>
    /// <typeparam name="T">The item type</typeparam>
    /// <typeparam name="P">The select parameter type</typeparam>
    /// <param name="savant">The savant instance.</param>
    /// <param name="command">The command.</param>
    /// <param name="paramValues">The param values.</param>
    /// <param name="paramName">Name of the param.</param>
    /// <returns></returns>
    public static List<T> SelectWithList<T,P>(ISimpleSavantU savant, SelectCommand<T> command, List<P> paramValues, string paramName)
    {
        var allValues = SelectAttributesWithList(savant, command, paramValues, paramName);
        var typedValues = new List<T>();
        foreach (var values in allValues)
        {
            typedValues.Add((T)PropertyValues.CreateItem(typeof (T), values));
        }
        return typedValues;
    }

    /// <summary>
    /// Invokes select queries that use parameter lists (with IN clauses) by splitting the parameter list
    /// across multiple invocations that are invoked in parallel.
    /// </summary>
    /// <typeparam name="P">The select parameter type</typeparam>
    /// <param name="savant">The savant instance.</param>
    /// <param name="command">The command.</param>
    /// <param name="paramValues">The param values.</param>
    /// <param name="paramName">Name of the param.</param>
    /// <returns></returns>
    public static List<PropertyValues> SelectAttributesWithList<P>(ISimpleSavantU savant, SelectCommand command, List<P> paramValues, string paramName)
    {
        Arg.CheckNull("savant", savant);
        Arg.CheckNull("command", command);
        Arg.CheckNull("paramValues", paramValues);
        Arg.CheckNullOrEmpty("paramName", paramName);

        var allValues = new List<PropertyValues>();
        if (paramValues.Count == 0)
        {
            return allValues;
        }

        var results = new List<IAsyncResult>();
        do
        {
            var currentParams = paramValues.Skip(results.Count * MaxValueTestsPerSimpleDbQuery).Take(MaxValueTestsPerSimpleDbQuery).ToList();
            if (!currentParams.Any())
            {
                break;
            }
            var currentCommand = Clone(command);
            currentCommand.Reset();
            var parameter = currentCommand.GetParameter(paramName);
            parameter.Values.Clear();
            parameter.Values.AddRange(currentParams.Select(e => (object)e));
            var result = savant.BeginSelectAttributes(currentCommand, null, null);
            results.Add(result);
        } while (true);

        foreach (var result in results)
        {
            var values = ((ISimpleSavant2)savant).EndSelectAttributes(result);
            allValues.AddRange(values);
        }

        return allValues;
    }

    private static SelectCommand Clone(SelectCommand command)
    {
        var newParameters = new List<CommandParameter>();
        foreach (var parameter in command.Parameters)
        {
            var newParameter = new CommandParameter(parameter.Name, parameter.PropertyName, null);
            newParameter.Values.Clear();
            newParameters.Add(newParameter);
        }
        var newCommand = new SelectCommand(command.Mapping, command.CommandText, newParameters.ToArray())
            {
                MaxResultPages = command.MaxResultPages
            };
        return newCommand;
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文