为 Azure DocumentDB 排序
Sorting for Azure DocumentDB
我想使用 DocumentDB 存储大约 200.000 个相同类型的文档。每个文档都有一个整数 id 字段,我想以相反的顺序(最高 id 在前)检索它们分页。
所以最近我发现 DocumentDB 没有排序(另请参阅 DocumentDB - query result order)。也许最好选择不同的数据库(例如 RavenDB),但是时间紧迫,我想避免切换到另一个数据库的成本。
问题:
我一直在考虑在客户端实现我自己的文档排序索引 (ASP Web API 2)。我正在考虑创建一个键(id)和值(document.selflink)的排序列表。然后我可以创建一个 Getter,其中包含用于计数、偏移量和过滤文档的谓词参数。下面我添加了一个简单的例子。
我只是觉得这是个坏主意;要么速度慢,耗费太多资源,要么可以通过其他方式更好地完成。所以我愿意接受实施建议...
public class SortableDocumentDbRepository
{
private SortedList _sorted = new SortedList();
private readonly string _sortedPropertyName;
private DocumentCollection ReadOrCreateCollection(string databaseLink) {
DocumentCollection col = base.ReadOrCreateCollection(databaseLink);
var docs = Client.CreateDocumentQuery(Collection.DocumentsLink)
.AsEnumerable();
lock (_sorted.SyncRoot) {
foreach (Document doc in docs) {
var propVal = doc.GetPropertyValue<string>(_sortedPropertyName);
if (propVal != null) {
_sorted.Add(propVal, doc.SelfLink);
}
}
}
return col;
}
public List<T> GetItems<T>(int count, int offset, Expression<Func<T, bool>> predicate) {
List<T> result = new List<T>();
lock (_sorted.SyncRoot) {
var values = _sorted.GetValueList();
for (int i = offset; i < _sorted.Count; i++) {
var queryable = predicate != null ?
Client.CreateDocumentQuery<T>(values[i].ToString()).Where(predicate) :
Client.CreateDocumentQuery<T>(values[i].ToString());
T item = queryable.AsEnumerable().FirstOrDefault();
if (item == null || item.Equals(default(T))) continue;
result.Add(item);
if (result.Count >= count) return result;
}
}
return result;
}
}
如您所述,不幸的是,order by 尚未实现。
我觉得你的方法很合理。
我看到您正在使用谓词来缩小查询结果集(为任何数据库提取 200,000 条记录的成本很高)。
因为您似乎希望通过 id
进行排序 - 您还可以考虑在 id
上设置范围索引,从而允许您执行范围查询(例如 <
和 >
) 在 id
上,进一步缩小查询结果集。 _ts
(时间戳)系统 属性 上的文档默认包含一个范围索引,在这方面也可能有帮助。
参见:http://azure.microsoft.com/en-us/documentation/articles/documentdb-indexing-policies/
Microsoft 已实现排序:
https://docs.microsoft.com/en-us/azure/cosmos-db/sql-api-sql-query-reference#bk_orderby_clause
示例:SELECT * FROM c ORDER BY c._ts DESC
我想使用 DocumentDB 存储大约 200.000 个相同类型的文档。每个文档都有一个整数 id 字段,我想以相反的顺序(最高 id 在前)检索它们分页。
所以最近我发现 DocumentDB 没有排序(另请参阅 DocumentDB - query result order)。也许最好选择不同的数据库(例如 RavenDB),但是时间紧迫,我想避免切换到另一个数据库的成本。
问题: 我一直在考虑在客户端实现我自己的文档排序索引 (ASP Web API 2)。我正在考虑创建一个键(id)和值(document.selflink)的排序列表。然后我可以创建一个 Getter,其中包含用于计数、偏移量和过滤文档的谓词参数。下面我添加了一个简单的例子。
我只是觉得这是个坏主意;要么速度慢,耗费太多资源,要么可以通过其他方式更好地完成。所以我愿意接受实施建议...
public class SortableDocumentDbRepository
{
private SortedList _sorted = new SortedList();
private readonly string _sortedPropertyName;
private DocumentCollection ReadOrCreateCollection(string databaseLink) {
DocumentCollection col = base.ReadOrCreateCollection(databaseLink);
var docs = Client.CreateDocumentQuery(Collection.DocumentsLink)
.AsEnumerable();
lock (_sorted.SyncRoot) {
foreach (Document doc in docs) {
var propVal = doc.GetPropertyValue<string>(_sortedPropertyName);
if (propVal != null) {
_sorted.Add(propVal, doc.SelfLink);
}
}
}
return col;
}
public List<T> GetItems<T>(int count, int offset, Expression<Func<T, bool>> predicate) {
List<T> result = new List<T>();
lock (_sorted.SyncRoot) {
var values = _sorted.GetValueList();
for (int i = offset; i < _sorted.Count; i++) {
var queryable = predicate != null ?
Client.CreateDocumentQuery<T>(values[i].ToString()).Where(predicate) :
Client.CreateDocumentQuery<T>(values[i].ToString());
T item = queryable.AsEnumerable().FirstOrDefault();
if (item == null || item.Equals(default(T))) continue;
result.Add(item);
if (result.Count >= count) return result;
}
}
return result;
}
}
如您所述,不幸的是,order by 尚未实现。
我觉得你的方法很合理。
我看到您正在使用谓词来缩小查询结果集(为任何数据库提取 200,000 条记录的成本很高)。
因为您似乎希望通过 id
进行排序 - 您还可以考虑在 id
上设置范围索引,从而允许您执行范围查询(例如 <
和 >
) 在 id
上,进一步缩小查询结果集。 _ts
(时间戳)系统 属性 上的文档默认包含一个范围索引,在这方面也可能有帮助。
参见:http://azure.microsoft.com/en-us/documentation/articles/documentdb-indexing-policies/
Microsoft 已实现排序: https://docs.microsoft.com/en-us/azure/cosmos-db/sql-api-sql-query-reference#bk_orderby_clause
示例:SELECT * FROM c ORDER BY c._ts DESC