Как получить последнюю запись с помощью RowKey или Timestamp в хранилище таблиц Azure

Сложная часть RowKey является string который имеет значение, как Mon Nov 14 12:26:42 2016

Я пробовал использовать запрос Timestamp лайк

var lowerlimit = DateTime.UtcNow; // its should be nearer to table timestamp data.
            TableQuery<TemperatureEntity> query2 = new TableQuery<TemperatureEntity>().Where(TableQuery.GenerateFilterConditionForDate("Timestamp", QueryComparisons.GreaterThanOrEqual,lowerlimit));
            var test = table.ExecuteQuery(query2);

MyEntity.cs

  public class MyEntity : TableEntity
    {
        public MyEntity(string partitionKey, string rowKey)
        {
            this.PartitionKey = partitionKey;
            this.RowKey = rowKey;
        }

        public MyEntity() { }

        public Int64 DevideId { get; set; }

        public string RowKey { get; set; }
    }

// ниже запроса выдает полные данныеProgram.cs

// Retrieve the storage account from the connection string.
            CloudStorageAccount storageAccount = CloudStorageAccount.Parse(
                CloudConfigurationManager.GetSetting("StorageConnectionString"));

            // Create the table client.
            CloudTableClient tableClient = storageAccount.CreateCloudTableClient();

            // Create the CloudTable object that represents the "TemperatureData" table.
            CloudTable table = tableClient.GetTableReference("TemperatureData");

            // retrive data
            TableQuery<TemperatureEntity> query = new TableQuery<TemperatureEntity>();
            var data = table.ExecuteQuery(query);

введите описание изображения здесь

2 ответа

Решение

Нео,

Если вам нужна последняя запись в вашем разделе, использование строковой даты и времени для ключа строки не является хорошим подходом, поскольку хранилище таблиц сохраняет сущности в порядке возрастания на основе ключа строки.

Если в текущей точке вы можете изменить значение вашего ключа строки, используйте DateTime.UtcNow.Ticks:

var invertedTimeKey = DateTime.MaxValue.Ticks - DateTime.UtcNow.Ticks

При таком подходе при запросе таблицы вы сможете получить 1 запись, соответствующую самой последней.

Если вы не можете изменить значение ключа строки, вам придется извлечь все записи в разделе, то есть загрузить все их в память, а затем упорядочить их, используя метку времени, чтобы получить последнюю. Если у вас много записей, это определенно не очень хороший подход.

var lastResult = results.OrderByDescending(r => r.Timestamp).FirstOrDefault();

Служба таблиц Azure не поддерживает Order By функциональность, таким образом, с помощью текущей настройки только для вас, чтобы загрузить все объекты и отсортировать их в обратном порядке на клиентской стороне. Это, очевидно, не является оптимальным решением, когда число объектов в таблице становится большим.

Другой вариант (который потребует от вас изменения дизайна приложения) - преобразовать значение даты / времени в обратные тики:

var rowKey = (DateTime.MaxValue.Ticks - DateTimeValueForRowKey.Ticks).ToString("d19")

Это обеспечит добавление последних записей в верхнюю часть таблицы, а не в нижнюю часть таблицы. Чтобы получить последнюю запись, вам нужно просто взять 1-ю сущность из таблицы.

Другой подход, который может хорошо работать в некоторых ситуациях, - это "умный перебор" таблицы путем создания запроса диапазона или набора запросов диапазона для значений, которые, как вы ожидаете, будут работать, и их одновременное отключение..

В этом случае, поскольку ключ строки находится в формате Mon Nov 14 12:26:42 2016(и предположим, что OP @neo не может его изменить), и им нужны самые последние результаты, тогда вы можете получить хорошую производительность с помощью префиксного запроса (который по-прежнему является лексикографическим запросом диапазона), который, по словам Azure, является самым быстрым тип неточного запроса:

Вторым лучшим является запрос диапазона, который использует PartitionKey и фильтры по ряду RowKeyзначения для возврата более одной сущности. ВPartitionKey значение определяет конкретный раздел, а RowKeyзначения идентифицируют подмножество сущностей в этом разделе. Например:$filter=PartitionKey eq 'Sales' and RowKey ge 'S' and RowKey lt 'T'.

Изящный трюк, чтобы заставить эту работу работать, заключается в том, чтобы воспользоваться тем фактом, что Mon Nov 14 будут только эти даты:

1977-11-14
1983-11-14
1988-11-14
1994-11-14
2005-11-14
2011-11-14
2016-11-14
2022-11-14
2033-11-14
2039-11-14
2044-11-14
etc

Итак, просто выполняя поиск по префиксу Mon Nov 14 безопасно вернет записи за неявно желаемый год (2016) и, возможно, за 1 или 2 других года, которые можно безопасно исключить в памяти без значительного снижения производительности (например, 2011 и 2022).

Обратите внимание, что Azure использует реальный запрос диапазона только в том случае, если вы указываете точное значение для PartitionKey, который в этом случае всегда "raspberrypi". Исходный запрос OP - нет.

String partitionKeyFilter = TableQuery.GenerateFilterCondition(
    propertyName: "PartitionKey",
    operation   : QueryComparisons.Equal,
    givenValue  : "raspberrypi"
);

DateTime today = DateTime.UtcNow;
String todayPrefix = today.ToString( "ddd MMM dd", CultureInfo.InvariantCulture );

String rowKeyFilter = TableQuery.GenerateFilterCondition(
    propertyName: "RowKey",
    operation   : QueryComparisons.GreaterThan,
    givenValue  : todayPrefix 
);

TableQuery<TemperatureEntity> query = new TableQuery<TemperatureEntity>()
{
    FilterString = TableQuery.CombineFilters( partitionKeyFilter, TableOperators.And, rowKeyFilter );
}

List<TemperatureEntity> queryResults = table
    .ExecuteQuery( query )
    .Where( e => e.RowKey.EndsWith( today.ToString(" yyyy") ) ) // Filter current-year in the client.
    .ToList();
Другие вопросы по тегам