2

ブログ投稿を保存するために azure テーブル ストレージを使用しています。各ブログ投稿には異なるタグを付けることができます。だから私は3つの異なるテーブルを持つつもりです。

  • ブログの投稿を保存するもの。
  • タグを格納するための 1 つ
  • タグと投稿の関係を保存するもの

私の質問は次のとおりです。動的検索クエリを作成することは可能ですか? 検索するタグの数は、実行時までわからないためです。私が理解しているように、LINQを使用してのみAzureテーブルをクエリできます。または、動的に変更できる文字列クエリを入力できますか?

アップデート

ブログ テーブルにあるデータの例を次に示します。

PartitionKey,RowKey,Timestamp,Content,FromUser,Tags
user1, 1, 2012-08-08 13:57:23, "Hello World", "root", "yellow,red"

blogTag テーブル

PartitionKey,RowKey,Timestamp,TagId,TagName
"red", "red", 2012-08-08 11:40:29, 1, red
"yellow", "yellow", 2012-08-08 11:40:29, 2, yellow

関係表

PartitionKey,RowKey,Timestamp,DataId,TagId
1, 1, 2012-08-08 11:40:29, 1, 1
2, 1, 2012-08-08 13:57:23, 1, 2

これらのテーブルの使用例の 1 つは、たとえば、特定のタグを持つすべてのブログ投稿を取得する場合です。

  • blogTag テーブルから tagId を照会する必要があります
  • その後、関係テーブルで dataId を検索する必要があります
  • 最後に、その dataId を持つブログ投稿のブログ テーブルを検索する必要があります。

私はLINQを使用してクエリを実行していますが、次のようになります

CloudTableQuery<DataTag> tagIds = (from e in ctx2.CreateQuery<DataTag>("datatags")
                                   where e.PartitionKey == tags
                                   select e).AsTableServiceQuery<DataTag>();

フィルターを使用する Gaurav Mantri の提案を試してみましたが、うまくいきました。しかし、その効率がどうなるかが心配です。そして、許可されている 15 個の離散比較の制限について。

4

4 に答える 4

1

私もまったく同じ問題に直面しています。私は以下に貼り付けている1つの解決策を見つけました:

public static IEnumerable<T> Get(CloudStorageAccount storageAccount, string tableName, string filter)
    {
        string tableEndpoint = storageAccount.TableEndpoint.AbsoluteUri;
        var tableServiceContext = new TableServiceContext(tableEndpoint, storageAccount.Credentials);
        string query = string.Format("{0}{1}()?filter={2}", tableEndpoint, tableName, filter);
        var queryResponse = tableServiceContext.Execute<T>(new Uri(query)) as QueryOperationResponse<T>;
        return queryResponse.ToList();
    }

基本的に、DataServiceContext の Execute(Uri) メソッドを利用します: http://msdn.microsoft.com/en-us/library/cc646700.aspx

REST API を介してクエリ機能を呼び出す場合と同様に、フィルター条件を指定する必要があります (例: PartitionKey eq 'mypk' および RowKey ge 'myrk')。これが最善の解決策かどうかはわかりません:)これに関するコメントを楽しみにしています。

于 2012-08-09T13:54:24.687 に答える
0

このようなものをテーブル ストレージに構築するのは非常に面倒です。丸い穴に四角いペグを押し込むようなものです。

代わりに、ブロブ ストレージを使用してブログを保存し、Lucene.NET を使用してタグの検索を実装することを検討できます。Lucene は、(Tag = "A" and Tag = "B" and Tag != "C") のようなより複雑な検索も許可し、さらに、必要に応じてブログ テキスト自体の検索も許可します。

http://code.msdn.microsoft.com/windowsazure/Azure-Library-for-83562538

于 2012-08-09T16:01:41.353 に答える
0

それは可能ですが、良い考えではないかもしれません。このように複数のクエリ パラメータを追加すると、常にテーブル スキャンが発生します。小さなテーブルではおそらく問題ありませんが、テーブルが大きくなると非常に遅くなります。大きなテーブルの場合は、キーの組み合わせごとに個別のクエリを実行することをお勧めします。

とはいえ、LINQ マジックを使用して動的クエリを作成することもできます。そのために使用したヘルパー クラスを次に示します。

public class LinqBuilder
{
    /// <summary>
    /// Build a LINQ Expression that roughly matches the SQL IN() operator
    /// </summary>
    /// <param name="columnValues">The values to filter for</param>
    /// <returns>An expression that can be passed to the LINQ  .Where() method</returns>
    public static Expression<Func<RowType, bool>> BuildListFilter<RowType, ColumnType>(string filterColumnName, IEnumerable<ColumnType> columnValues)
    {
        ParameterExpression rowParam = Expression.Parameter(typeof(RowType), "r");
        MemberExpression column = Expression.Property(rowParam, filterColumnName);

        BinaryExpression filter = null;
        foreach (ColumnType columnValue in columnValues)
        {
            BinaryExpression newFilterClause = Expression.Equal(column, Expression.Constant(columnValue));
            if (filter != null)
            {
                filter = Expression.Or(filter, newFilterClause);
            }
            else
            {
                filter = newFilterClause;
            }
        }

        return Expression.Lambda<Func<RowType, bool>>(filter, rowParam);
    }

    public static Expression<Func<RowType, bool>> BuildComparisonFilter<RowType, ColumnType>(string filterColumnName, Func<MemberExpression, BinaryExpression> buildComparison)
    {
        ParameterExpression rowParam = Expression.Parameter(typeof(RowType), "r");
        MemberExpression column = Expression.Property(rowParam, filterColumnName);

        BinaryExpression filter = buildComparison(column);
        return Expression.Lambda<Func<RowType, bool>>(filter, rowParam);
    }

}

次のように使用します。

var whereClause = BuildListFilter(queryColumnName, columnValues);
CloudTableQuery<RowType> query = (from r in tableServiceContext.CreateQuery<MyRow>("MyTable")
                                    where r.PartitionKey == partitionKey
                                    select r)
                                    .Where(whereClause) //Add in our multiple where clauses
                                    .AsTableServiceQuery(); //Convert to table service query
var results = query.ToList();

テーブル サービスでは、クエリごとに最大数の制約が適用されることにも注意してください。文書化された最大値はクエリごとに 15 ですが、これを最後に試したとき (少し前)、実際の最大値は 14 でした。

于 2012-08-09T14:58:30.543 に答える