Search API詳細解説シリーズ
タイトル | |
Part1 | Search API 概要説明 |
Part2 | Search APIの使い方 登録・削除編 |
Part3 | Search APIの使い方 検索編(このページです) |
Part4 | Search API 詳細 検索性能編 |
Part5 | Search API 詳細 反映速度編 |
Part6 | Search API 詳細 限界値編 |
みなさん、こんにちは。
前回はSearch API詳細解説のPart2「Search APIの使い方 登録・削除編」でしたので、今回はSearch API詳細解説のPart3「Search APIの使い方 検索編」です。
この検索編では、
- 一番簡単な検索
- 検索条件を指定した検索
- 検索オプションを指定した検索
- 検索結果の取り扱い方
の4つを説明したいと思います。
今回の検索編をやるにあたり、検索対象のIndex, Document, FieldはPart2「Search APIの使い方 登録・削除編」の登録パートで登録したDocumentのFieldを前提に話を進めていきます。
検索対象のIndexのDocumentのFieldの定義は以下のようになっていたかと思います。
Field名 | FieldType |
name | TEXT |
booleanType | ATOM |
birtyDay | DATE |
html | HTML |
geoPoint | GEO_POINT |
age | NUMBER |
category | TEXT |
一番簡単な検索処理の実装
それでは早速検索処理を実装してみましょう。
登録処理の実装と同じで、基本的にはBuilderを使用して検索条件などを設定しますので、メソッドの使い方を間違わなければ簡単に実装できるかと思います。
import com.google.appengine.api.search.Index;
import com.google.appengine.api.search.IndexSpec;
// ……中略……
// 事前準備として、Search APIのIndexオブジェクトを作成します。
// Index名「simple」に対しての検索を行なうようにsetNameには「simple」を設定します。
IndexSpec indexSpec = IndexSpec.newBuilder().setName("simple").build();
Index index = SearchServiceFactory.getSearchService().getIndex(indexSpec);
// 検索処理
// index.searchの引数を空文字にすると、検索条件なしで検索処理が実行されます。
Results<ScoredDocument> results = index.search(“”);
Index名だけを指定した検索ですので、これが一番簡単な検索処理の実装かと思います。
検索条件を指定して検索する
次は検索条件を指定して、検索処理を実装してみましょう。
※indexオブジェクトは「一番簡単な検索処理の実装」と同じ手順で作成しますので、割愛します。
検索条件が一つの場合
Filed名「name」に対して、「テスト」を含むDocumentを検索します。
import com.google.appengine.api.search.Query;
// ……中略……
// クエリの作成
Query q = Query.newBuilder().build("name=テスト"); // 検索条件を指定します。
// 検索処理
Results<ScoredDocument> results = index.search(q);
前述した「一番簡単な検索処理の実装」ではIndex.searchに空文字を設定しましたが、今度はQueryオブジェクトを設定して、検索処理を実行します。
検索条件のFieldTypeがNumberやDATEであっても検索条件に指定する場合は、文字列で扱わなければなりませんの気を付けてください。
また、FieldType.DATEの場合は検索値のフォーマットに気を付けなければなりません。
FieldType.DATEのフィールドを検索する場合は、「yyyy-MM-dd」のフォーマットの文字列でなければ、エラーになってしまいます。
// 日付型のFieldに対するクエリ例
Query q = Query.newBuilder().build("birtyDay=2015-01-31");
フォーマットからも分かると思いますが、FieldType.DATE型は時分秒は検索対象になりませんので検索項目として使う場合は気を付けてください。
Part1「Search API 概要説明」で私はSearch APIについて、『検索条件を柔軟に指定できる』ことを利点として上げました。
Datastoreとは違い、Search APIでは複数の検索条件が自由に設定できますので、次は複数の条件の検索処理を書いてましょう。
検索条件が複数の場合
検索条件にはAND、ORを自由に使用することができます。
import com.google.appengine.api.search.Query;
// ……中略……
// クエリの作成
Query q = Query.newBuilder().build("name=テスト AND age=25"); // ANDで検索条件を指定します。
// 検索処理
Results<ScoredDocument> results = index.search(q);
オプションを指定して検索する
取得できる件数を増やす
条件を指定して検索は出来ましたが、前述した実装では取得できる検索結果は最大で20件しか取れません。
これはSearch APIの仕様で、デフォルトで取得できる結果の件数が20件になっているからです。
検索結果を増やすためには以下のコードのようにSearch APIのオプションで取得する件数を設定指定しなければなりません。
import com.google.appengine.api.search.Query;
// ……中略……
// オプションを作成。setLimitに1000を指定
QueryOptions options = QueryOptions.newBuilder().setLimit(1000).build();
// クエリの作成時に作成したQueryOptionsオブジェクトを設定します。
Query q = Query.newBuilder().setOptions(options).build("name=テスト AND age=25");
// 検索処理
Results<ScoredDocument> results = index.search(q);
setLimitに指定できる最大件数は1000件までです。
1000件以上取得したい場合は、後述する検索結果の戻り値である「Results<ScoredDocument>」オブジェクトからCursorを取り出し、そのCursorがNULLになるまで検索を繰り返す、という方法しかないと思います。
※QueryOptionsにsetOffsetはありますが、これには1000以下の値しか設定できないため、やはりCursorを使うしかありません。
ソートして検索する
Search APIではソート順も下記コードのように指定することができます。
※ソート順を指定しない場合はDocumentの登録が新しいものが上にきます。
import com.google.appengine.api.search.SortExpression;
import com.google.appengine.api.search.SortOptions;
// ……中略……
// ソートの設定を作成します。
SortExpression expression = SortExpression.newBuilder()
.setExpression("name")// ソート対象のフィールドを指定する
.setDirection(SortExpression.SortDirection.ASCENDING)// ソート順を指定する
.setDefaultValue("") // ソート対象のフィールド値が空だった場合のためにデフォルト値を指定します。
.build();
// ソートオプションを作成します。
SortOptions sortOptions = SortOptions.newBuilder()
.addSortExpression(expression) // ソートの設定を追加します。
.build();
// ソートオプジョンをクエリオプションに設定する。
QueryOptions options = QueryOptions.newBuilder()
.setSortOptions(sortOptions)
.setLimit(1000)
.build();
// クエリオプションを設定して、クエリを作成する。
Query q = Query.newBuilder().setOptions(options).build("");
// 検索処理
Results<ScoredDocument> results = index.search(q);
上記コードを実行した場合、フィールド名「name」の昇順で検索結果が返るようになります。
検索結果を扱う
ここまで、検索処理の実装についてはいろいろ分かっていただけたかと思います。
今度は検索結果について、検索画面を思い浮かべた時に使いそうなものと、取得できたDocumentのデータからFieldの値を取り出すまでを書いてみましょう。
import com.google.appengine.api.search.Cursor;
import com.google.appengine.api.search.ScoredDocument;
// ……中略……
// 検索処理
Results<ScoredDocument> results = index.search(q);
// 検索結果でよく使う値
Cursor cursor = results.getCursor(); // 取得できた検索結果の続きを取得するためのカーソル
long numberFound = results.getNumberFound(); // 検索条件で引っかかった合計件数です。
Collection<ScoredDocument> scoredDocuments = results.getResults(); // Documentの一覧
// 検索結果のDocumentのデータを扱う。
for (ScoredDocument scoredDocument : scoredDocuments) {
// DocumentのIDを取得できます。Documentの削除に使用します。
String docId = scoredDocument.getId();
// Documentが持つフィールドの一覧とその値を取得してみます。
Iterable<Field> fields = scoredDocument.getFields();
for (Field field : fields) {
String fieldName = field.getName(); // フィールド名
FieldType fieldType = field.getType(); // FieldType
// FieldTypeにあったgetterから値を取得します。
if (fieldType == FieldType.ATOM) {
String atom = field.getAtom();
} else if (fieldType == FieldType.DATE) {
Date date = field.getDate();
} else if (fieldType == FieldType.GEO_POINT) {
GeoPoint geoPoint = field.getGeoPoint();
} else if (fieldType == FieldType.HTML) {
String html = field.getHTML();
} else if (fieldType == FieldType.NUMBER) {
Double number = field.getNumber();
} else if (fieldType == FieldType.TEXT) {
String text = field.getText();
}
}
}
FieldTypeに合ったgetterからでしか値を取得できないのは少し面倒ですね。
ここまでで、Search APIへのデータの登録・削除・検索までをやってきました。
これで一通りの実装はできるようになったのではないかと思います。
次回は、Search APIの検索精度について色々試してみたいと思います。
Search API詳細解説シリーズ
タイトル | |
Part1 | Search API 概要説明 |
Part2 | Search APIの使い方 登録・削除編 |
Part3 | Search APIの使い方 検索編(このページです) |
Part4 | Search API 詳細 検索性能編 |
Part5 | Search API 詳細 反映速度編 |
Part6 | Search API 詳細 限界値編 |