Sitecore Commerceで製品やカテゴリを検索する方法
Tags: sitecore, commerce, contentsearch
Published: 2020-02-05 05:05:31

Sitecore Commerceでは、コマースエンジン側に作成したSellable ItemやCategoryはデータプロバイダーを通じてSitecore側でアイテムとして扱えるようになっています。  
このアイテムはコマース用のクローラーでインデックスに追加されているので、Content Search APIを使用することで簡単に検索することができます。

## 検索方法
Content Search APIでカタログ関連のアイテムを検索するには、ドキュメントの型に以下のクラスを使用します。  

- `CommerceCatalogSearchResultItem`
- `CommerceCategorySearchResultItem`
- `CommerceSellableItemSearchResultItem`


検索するカタログアイテムに応じて使い分けてください。クラス定義は以下のアセンブリに含まれています。

- Sitecore.Commerce.Engine.Connect.dll

以下の例では、表示名の部分一致検索でSellable Itemを探しています。

```cs
public List<Item> SearchSellableItemByDisplayName(string displayName)
{
    // 検索インデックスを取得（デフォルトではsitecore_master(web)_indexを取得します）
    var searchManager = CommerceTypeLoader.CreateInstance<ICommerceSearchManager>();
    var index = searchManager.GetIndex();

    using (var context = index.CreateSearchContext())
    {
        var queryable = context.GetQueryable<CommerceSellableItemSearchResultItem>();
        var results = queryable
            .Filter(item => item.CommerceSearchItemType == "SellableItem")  // Sellable Itemに絞り込み
            .Filter(item => item.Language == Sitecore.Context.Language.Name)
            .Filter(item => item["_latestversion"] == "1")  // 最新のバージョンのみ
            .Filter(item => item.DisplayName.Contains(displayName))  // 表示名の部分一致
            .GetResults();

        return results.Hits.Select(item => item.Document.GetItem()).ToList();
    }
}
```

sitecore_master_indexには全アイテムの定義が含まれているので、`CommerceSearchItemType`プロパティを使ってSellable Itemのみに絞り込んでいます。  
このプロパティには以下の値のいずれかが含まれるので、検索するカタログアイテムに応じて使用してください。

- `"SellableItem"`
- `"Category"`
- `"Catalog"`
- `"Navigation"`
- `"Unknown"`

また`Language`や`_latestversion`での絞り込みを行わないと全言語・数値バージョンのアイテムが取得されるため注意してください。  

取得できるアイテムは、コンテンツエディタ上に表示されるSellable Itemと同じフィールド値を持っています。  

さらに、以下のように特定のカタログやカテゴリのSellable Itemに絞り込むこともできます。  

```cs
// カタログ配下のアイテムに絞り込み
queryable = queryable.Filter(item => item.Paths.Contains(catalogId));

// カテゴリ配下のアイテムに絞り込み
queryable = queryable.Filter(item => item.CommerceAncestorIds.Contains(categoryId));
```

## ページネーション
`CommerceSearchOptions`を使うことでページネーションを簡単に実装できます。（もちろん、使わなくても実装可能です）

```cs
var searchManager = CommerceTypeLoader.CreateInstance<ICommerceSearchManager>();
var index = searchManager.GetIndex();

using (var context = index.CreateSearchContext())
{
    var queryable = context.GetQueryable<CommerceSellableItemSearchResultItem>()
        .Filter(item => item.CommerceSearchItemType == "SellableItem")
        .Filter(item => item.Language == Sitecore.Context.Language.Name)
        .Filter(item => item["_latestversion"] == "1")
        .GetResults();

    // 検索オプション
    var options = new CommerceSearchOptions
    {
        NumberOfItemsToReturn = 20, // Limit
        StartPageIndex = 0,  // Offset
        SortField = "Date",
        SortDirection = CommerceConstants.SortDirection.Desc
    };

    // オプションをクエリに適用
    queryable = searchManager.AddSearchOptionsToQuery(queryable, options);

    // ページネーション用の結果を取得
    var response = SearchResponse.CreateFromSearchResultsItems(options, queryable.GetResults());

    var items = response.ResponseItems; // 指定したページのアイテム一覧
    var total = response.TotalItemCount;  // 総ヒット数
    var pages = response.TotalPageCount;  // 総ページ数
}
```

## 注意点・補足
このコードは、ストアフロントのコンテキスト（コンポーネントのリポジトリ内など）で実行される必要があります。  
ストアフロント外で実行されると、`Document.GetItem`がnullを返してしまうようです。