Запрос Amazon SimpleDB для поиска "сообщения от друзей" - PullRequest
2 голосов
/ 06 августа 2010

Я разрабатываю приложение для iPhone, которое запрашивает сервер, который передает данные, которые я храню в Amazon SimpleDB.У меня есть таблица базы данных "Представления" различными пользователями.Я подключаюсь к Facebook, чтобы найти друзей из Facebook, и хочу сделать запрос в «Материалы», чтобы найти сообщения от друзей, например:

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

(через полный список друзей)

Iдумаю, что это приведет к пределу запросов Amazon с этим видом оператора выбора -

[Максимальное количество сравнений на выражение Select: 20]

Можете ли вы придумать способ элегантно выполнить этос SimpleDB?Я бы предпочел не делать кучу запросов из 20 человек.Или мне нужно перейти к другому пакету базы данных, а затем выполнить кросс-таблицы?

Спасибо!

Ответы [ 3 ]

4 голосов
/ 06 августа 2010

Есть способ сделать это с SimpleDB, но это не элегантно, это скорее хак, так как требует искусственного дублирования атрибута userid в ваших элементах представления.

Это основано на том факте, что хотя вы можете иметь только 20 сравнений на один предикат IN, вы можете иметь 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 соответствует потребностям вашего приложения, за исключением этой проблемы, то подумайте об использовании хака. Но если вам нужно делать такие вещи неоднократно, то SimpleDB, вероятно, не лучший выбор.

2 голосов
/ 06 августа 2010

Вам нужно либо предложение IN, либо соединение с временной таблицей. К сожалению, AmazonSimpleDB имеет свои ограничения. Именно по этой причине мы отказались от него на перспективном проекте. Мы пошли по пути многопоточности и использования функциональности NextToken, прежде чем переключать передачи.

Вы можете выполнять параллельные (многопоточные) запросы к SimpleDB для получения представлений, каждый запрос ищет до 20 идентификаторов пользователей, а затем объединяет результаты в один список. Тем не менее, возможно, пришло время подумать о переходе на MySQL или SQL Server, чтобы иметь возможность загрузить список идентификаторов в виде временной таблицы, а затем выполнить простое объединение для получения результатов.

1 голос
/ 16 сентября 2010

Я создал Simple Savant .NET библиотеку для SimpleDB , и у меня случайно обнаружился некоторый служебный код для разделения и выполнения параллельных запросов множественного выбора, в то время как ограничение 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;
    }
...