我注意到devserver或单元测试环境与生产环境中App Engine文本搜索游标的行为不一致。开发和单元测试环境似乎表现出与排序表达式结合使用的游标的错误。请考虑以下单元测试代码:
@Test
public void testQueryCursor( ) throws Exception
{
testQueryCursor("id_%02d"); // works
testQueryCursor("id_%d"); // fails
}
private void testQueryCursor( final String idFmt ) throws Exception
{
final int TEST_COUNT = 12;
final Index index =
SearchServiceFactory.getSearchService().getIndex(IndexSpec.newBuilder().setName("MY_TEST_IDX").build());
final List<String> docIds = new ArrayList<String>(TEST_COUNT);
try {
// populate some test data into an index
for (int i = 0; i < TEST_COUNT; i++) {
final String docId = String.format(idFmt, i);
final Document.Builder builder = Document.newBuilder().setId(docId);
builder.addField(Field.newBuilder().setName("some_field").setText("str1 " + docId)); // include varied docId in field for sorting
index.put(builder.build());
docIds.add(docId);
}
// for comparison to sorted search results
Collections.sort(docIds);
// define query options
final QueryOptions.Builder optionsBuilder =
QueryOptions
.newBuilder()
.setReturningIdsOnly(true)
.setLimit(10)
.setSortOptions(
SortOptions
.newBuilder()
.setLimit(20)
.addSortExpression(
SortExpression.newBuilder().setExpression("some_field")
.setDirection(SortDirection.ASCENDING).setDefaultValue("")));
// see https://developers.google.com/appengine/docs/java/search/results#Java_Using_cursors
// create an initial per-query cursor
Cursor cursor = Cursor.newBuilder().build();
final Iterator<String> idIter = docIds.iterator();
int batchIdx = 0;
do {
// build options and query
final QueryOptions options = optionsBuilder.setCursor(cursor).build();
final Query query = Query.newBuilder().setOptions(options).build("some_field : str1");
// search at least once
final Results<ScoredDocument> results = index.search(query);
int batchCount = 0;
for (final ScoredDocument match : results) {
batchCount++;
assertTrue(idIter.hasNext());
assertEquals(idIter.next(), match.getId());
System.out.println("Document " + match.getId() + " matched.");
}
System.out.println("Read " + batchCount + " results from batch " + ++batchIdx);
cursor = results.getCursor();
} while (cursor != null);
} finally {
index.delete(docIds);
}
}
如果assertEquals(idIter.next(), match.getId());
行被注释掉以前失败的调用的完整输出,则可以观察到testQueryCursor("id_%d")
,并且我们看到结果的正确排序似乎被忽略。而且,对光标执行的最后一次搜索重复从先前搜索调用中检索的最后两个元素。由于这两个元素应该是搜索返回的最后两个元素,或许这种行为只是导致不正确排序的缺陷的工件。
此代码可以像这里所示的单元测试一样轻松运行,也可以从devserver上的JSP运行,行为一致。当在App Engine的生产实例上作为JSP运行时,行为的不同之处在于搜索在所有情况下都返回正确排序的结果。如果修复了devserver环境和单元测试工具以提供与生产一致的正确行为,那将是很好的。