Author: nwellnhof
Date: Thu May 17 14:41:22 2012
New Revision: 1339618
URL: http://svn.apache.org/viewvc?rev=1339618&view=rev
Log:
LUCY-228 Convert t/511-sort_spec.t to C
Added:
lucy/trunk/core/Lucy/Test/Search/TestSortSpec.c
lucy/trunk/core/Lucy/Test/Search/TestSortSpec.cfh
lucy/trunk/perl/t/binding/511-sort_spec.t
lucy/trunk/perl/t/core/511-sort_spec.t
Removed:
lucy/trunk/perl/t/511-sort_spec.t
Modified:
lucy/trunk/perl/buildlib/Lucy/Build/Binding/Misc.pm
Added: lucy/trunk/core/Lucy/Test/Search/TestSortSpec.c
URL:
http://svn.apache.org/viewvc/lucy/trunk/core/Lucy/Test/Search/TestSortSpec.c?rev=1339618&view=auto
==============================================================================
--- lucy/trunk/core/Lucy/Test/Search/TestSortSpec.c (added)
+++ lucy/trunk/core/Lucy/Test/Search/TestSortSpec.c Thu May 17 14:41:22 2012
@@ -0,0 +1,636 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#define C_LUCY_TESTREVERSETYPE
+#include "Lucy/Util/ToolSet.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "Lucy/Test.h"
+#include "Lucy/Test/Search/TestSortSpec.h"
+#include "Lucy/Test/TestUtils.h"
+#include "Lucy/Search/SortSpec.h"
+
+#include "Lucy/Analysis/StandardTokenizer.h"
+#include "Lucy/Document/Doc.h"
+#include "Lucy/Document/HitDoc.h"
+#include "Lucy/Index/Indexer.h"
+#include "Lucy/Plan/FullTextType.h"
+#include "Lucy/Plan/NumericType.h"
+#include "Lucy/Plan/Schema.h"
+#include "Lucy/Plan/StringType.h"
+#include "Lucy/Search/Hits.h"
+#include "Lucy/Search/IndexSearcher.h"
+#include "Lucy/Search/SortRule.h"
+#include "Lucy/Store/RAMFolder.h"
+
+static CharBuf *air_cb;
+static CharBuf *airplane_cb;
+static CharBuf *bike_cb;
+static CharBuf *car_cb;
+static CharBuf *carrot_cb;
+static CharBuf *cat_cb;
+static CharBuf *float32_cb;
+static CharBuf *float64_cb;
+static CharBuf *food_cb;
+static CharBuf *home_cb;
+static CharBuf *int32_cb;
+static CharBuf *int64_cb;
+static CharBuf *land_cb;
+static CharBuf *name_cb;
+static CharBuf *nope_cb;
+static CharBuf *num_cb;
+static CharBuf *random_cb;
+static CharBuf *sloth_cb;
+static CharBuf *speed_cb;
+static CharBuf *unknown_cb;
+static CharBuf *unused_cb;
+static CharBuf *vehicle_cb;
+static CharBuf *weight_cb;
+
+static CharBuf *random_float32s_cb;
+static CharBuf *random_float64s_cb;
+static CharBuf *random_int32s_cb;
+static CharBuf *random_int64s_cb;
+
+static void
+S_init_strings() {
+ air_cb = CB_newf("air");
+ airplane_cb = CB_newf("airplane");
+ bike_cb = CB_newf("bike");
+ car_cb = CB_newf("car");
+ carrot_cb = CB_newf("carrot");
+ cat_cb = CB_newf("cat");
+ float32_cb = CB_newf("float32");
+ float64_cb = CB_newf("float64");
+ food_cb = CB_newf("food");
+ home_cb = CB_newf("home");
+ int32_cb = CB_newf("int32");
+ int64_cb = CB_newf("int64");
+ land_cb = CB_newf("land");
+ name_cb = CB_newf("name");
+ nope_cb = CB_newf("nope");
+ num_cb = CB_newf("num");
+ random_cb = CB_newf("random");
+ sloth_cb = CB_newf("sloth");
+ speed_cb = CB_newf("speed");
+ unknown_cb = CB_newf("unknown");
+ unused_cb = CB_newf("unused");
+ vehicle_cb = CB_newf("vehicle");
+ weight_cb = CB_newf("weight");
+
+ random_float32s_cb = CB_newf("random_float32s");
+ random_float64s_cb = CB_newf("random_float64s");
+ random_int32s_cb = CB_newf("random_int32s");
+ random_int64s_cb = CB_newf("random_int64s");
+}
+
+static void
+S_destroy_strings() {
+ DECREF(air_cb);
+ DECREF(airplane_cb);
+ DECREF(bike_cb);
+ DECREF(car_cb);
+ DECREF(carrot_cb);
+ DECREF(cat_cb);
+ DECREF(float32_cb);
+ DECREF(float64_cb);
+ DECREF(food_cb);
+ DECREF(home_cb);
+ DECREF(int32_cb);
+ DECREF(int64_cb);
+ DECREF(land_cb);
+ DECREF(name_cb);
+ DECREF(nope_cb);
+ DECREF(num_cb);
+ DECREF(random_cb);
+ DECREF(sloth_cb);
+ DECREF(speed_cb);
+ DECREF(unknown_cb);
+ DECREF(unused_cb);
+ DECREF(vehicle_cb);
+ DECREF(weight_cb);
+
+ DECREF(random_float32s_cb);
+ DECREF(random_float64s_cb);
+ DECREF(random_int32s_cb);
+ DECREF(random_int64s_cb);
+}
+
+TestReverseType*
+TestReverseType_new() {
+ TestReverseType *self = (TestReverseType*)VTable_Make_Obj(TESTREVERSETYPE);
+ return TestReverseType_init(self);
+}
+
+TestReverseType*
+TestReverseType_init(TestReverseType *self) {
+ return TestReverseType_init2(self, 1.0, false, true, true);
+}
+
+TestReverseType*
+TestReverseType_init2(TestReverseType *self, float boost, bool_t indexed,
+ bool_t stored, bool_t sortable) {
+ FType_init((FieldType*)self);
+ self->boost = boost;
+ self->indexed = indexed;
+ self->stored = stored;
+ self->sortable = sortable;
+ return self;
+}
+
+int32_t
+TestReverseType_compare_values(TestReverseType *self, Obj *a, Obj *b) {
+ UNUSED_VAR(self);
+ return Obj_Compare_To(b, a);
+}
+
+static Schema*
+S_create_schema() {
+ Schema *schema = Schema_new();
+
+ StandardTokenizer *tokenizer = StandardTokenizer_new();
+ FullTextType *unsortable = FullTextType_new((Analyzer*)tokenizer);
+ DECREF(tokenizer);
+
+ StringType *string_type = StringType_new();
+ StringType_Set_Sortable(string_type, true);
+
+ Int32Type *int32_type = Int32Type_new();
+ Int32Type_Set_Indexed(int32_type, false);
+ Int32Type_Set_Sortable(int32_type, true);
+
+ Int64Type *int64_type = Int64Type_new();
+ Int64Type_Set_Indexed(int64_type, false);
+ Int64Type_Set_Sortable(int64_type, true);
+
+ Float32Type *float32_type = Float32Type_new();
+ Float32Type_Set_Indexed(float32_type, false);
+ Float32Type_Set_Sortable(float32_type, true);
+
+ Float64Type *float64_type = Float64Type_new();
+ Float64Type_Set_Indexed(float64_type, false);
+ Float64Type_Set_Sortable(float64_type, true);
+
+ TestReverseType *reverse_type = TestReverseType_new();
+
+ Schema_Spec_Field(schema, name_cb, (FieldType*)string_type);
+ Schema_Spec_Field(schema, speed_cb, (FieldType*)int32_type);
+ Schema_Spec_Field(schema, sloth_cb, (FieldType*)reverse_type);
+ Schema_Spec_Field(schema, weight_cb, (FieldType*)int32_type);
+ Schema_Spec_Field(schema, int32_cb, (FieldType*)int32_type);
+ Schema_Spec_Field(schema, int64_cb, (FieldType*)int64_type);
+ Schema_Spec_Field(schema, float32_cb, (FieldType*)float32_type);
+ Schema_Spec_Field(schema, float64_cb, (FieldType*)float64_type);
+ Schema_Spec_Field(schema, home_cb, (FieldType*)string_type);
+ Schema_Spec_Field(schema, cat_cb, (FieldType*)string_type);
+ Schema_Spec_Field(schema, unused_cb, (FieldType*)string_type);
+ Schema_Spec_Field(schema, nope_cb, (FieldType*)unsortable);
+
+ DECREF(reverse_type);
+ DECREF(float64_type);
+ DECREF(float32_type);
+ DECREF(int64_type);
+ DECREF(int32_type);
+ DECREF(string_type);
+ DECREF(unsortable);
+
+ return schema;
+}
+
+static void
+S_refresh_indexer(Indexer **indexer, Schema *schema, RAMFolder *folder) {
+ if (*indexer) {
+ Indexer_Commit(*indexer);
+ DECREF(*indexer);
+ }
+ *indexer = Indexer_new(schema, (Obj*)folder, NULL, 0);
+}
+
+static void
+S_add_vehicle(Indexer *indexer, CharBuf *name, int32_t speed, int32_t sloth,
+ int32_t weight, CharBuf *home, CharBuf *cat) {
+ Doc *doc = Doc_new(NULL, 0);
+
+ Doc_Store(doc, name_cb, (Obj*)name);
+ Doc_Store(doc, home_cb, (Obj*)home);
+ Doc_Store(doc, cat_cb, (Obj*)cat);
+
+ CharBuf *string;
+ string = CB_newf("%i32", speed);
+ Doc_Store(doc, speed_cb, (Obj*)string);
+ DECREF(string);
+ string = CB_newf("%i32", sloth);
+ Doc_Store(doc, sloth_cb, (Obj*)string);
+ DECREF(string);
+ string = CB_newf("%i32", weight);
+ Doc_Store(doc, weight_cb, (Obj*)string);
+ DECREF(string);
+
+ Indexer_Add_Doc(indexer, doc, 1.0f);
+
+ DECREF(doc);
+}
+
+static void
+S_add_doc(Indexer *indexer, Obj *name_obj, CharBuf *cat, CharBuf *field_name) {
+ Doc *doc = Doc_new(NULL, 0);
+ CharBuf *name = Obj_To_String(name_obj);
+ Doc_Store(doc, name_cb, (Obj*)name);
+ Doc_Store(doc, cat_cb, (Obj*)cat);
+ if (field_name) {
+ Doc_Store(doc, field_name, (Obj*)name);
+ }
+ Indexer_Add_Doc(indexer, doc, 1.0f);
+ DECREF(name);
+ DECREF(doc);
+}
+
+typedef Obj* (*random_generator_t)();
+
+static Obj*
+S_random_string() {
+ size_t length = 1 + rand() % 10;
+ CharBuf *string = CB_new(length);
+ while (length--) {
+ uint32_t code_point = 'a' + rand() % ('z' - 'a' + 1);
+ CB_Cat_Char(string, code_point);
+ }
+ return (Obj*)string;
+}
+
+static Obj*
+S_random_int32() {
+ uint64_t num = TestUtils_random_u64();
+ return (Obj*)Int32_new(num & 0x7FFFFFFF);
+}
+
+static Obj*
+S_random_int64() {
+ uint64_t num = TestUtils_random_u64();
+ return (Obj*)Int64_new(num & 0x7FFFFFFFFFFFFFFFLL);
+}
+
+static Obj*
+S_random_float32() {
+ uint64_t num = TestUtils_random_u64();
+ return (Obj*)Float32_new((double)num * (10.0 / U64_MAX));
+}
+
+static Obj*
+S_random_float64() {
+ uint64_t num = TestUtils_random_u64();
+ return (Obj*)Float64_new((double)num * (10.0 / U64_MAX));
+}
+
+static VArray*
+S_add_random_objects(Indexer **indexer, Schema *schema, RAMFolder *folder,
+ random_generator_t rng, CharBuf *field_name,
+ CharBuf *cat) {
+ VArray *objects = VA_new(100);
+
+ for (int i = 0; i < 100; ++i) {
+ Obj *object = rng();
+ S_add_doc(*indexer, object, cat, field_name);
+ VA_Push(objects, object);
+ if (i % 10 == 0) {
+ S_refresh_indexer(indexer, schema, folder);
+ }
+ }
+
+ VA_Sort(objects, NULL, NULL);
+
+ for (int i = 0; i < 100; ++i) {
+ Obj *obj = VA_Fetch(objects, i);
+ CharBuf *string = Obj_To_String(obj);
+ VA_Store(objects, i, (Obj*)string);
+ }
+
+ return objects;
+}
+
+static VArray*
+S_test_sorted_search(IndexSearcher *searcher, CharBuf *query,
+ uint32_t num_wanted, ...) {
+ VArray *rules = VA_new(2);
+ CharBuf *field;
+ va_list args;
+
+ va_start(args, num_wanted);
+ while (NULL != (field = va_arg(args, CharBuf*))) {
+ bool_t reverse = va_arg(args, bool_t);
+ SortRule *rule = SortRule_new(SortRule_FIELD, field, reverse);
+ VA_Push(rules, (Obj*)rule);
+ }
+ va_end(args);
+ SortRule *rule = SortRule_new(SortRule_DOC_ID, NULL, 0);
+ VA_Push(rules, (Obj*)rule);
+ SortSpec *spec = SortSpec_new(rules);
+
+ Hits *hits = IxSearcher_Hits(searcher, (Obj*)query, 0, num_wanted, spec);
+
+ VArray *results = VA_new(10);
+ ViewCharBuf *name = (ViewCharBuf*)ZCB_BLANK();
+ HitDoc *hit_doc;
+ while (NULL != (hit_doc = Hits_Next(hits))) {
+ HitDoc_Extract(hit_doc, name_cb, name);
+ VA_Push(results, (Obj*)CB_Clone((CharBuf*)name));
+ DECREF(hit_doc);
+ }
+
+ DECREF(hits);
+ DECREF(spec);
+ DECREF(rules);
+
+ return results;
+}
+
+typedef struct SortContext {
+ IndexSearcher *searcher;
+ CharBuf *sort_field;
+} SortContext;
+
+static void
+S_attempt_sorted_search(void *context) {
+ SortContext *sort_ctx = (SortContext*)context;
+ VArray *results = S_test_sorted_search(sort_ctx->searcher, vehicle_cb, 100,
+ sort_ctx->sort_field, false, NULL);
+ DECREF(results);
+}
+
+static void
+test_sort_spec(TestBatch *batch) {
+ RAMFolder *folder = RAMFolder_new(NULL);
+ Schema *schema = S_create_schema();
+ Indexer *indexer = NULL;
+ VArray *wanted = VA_new(10);
+ VArray *results;
+ VArray *results2;
+
+ // First, add vehicles.
+ S_refresh_indexer(&indexer, schema, folder);
+ S_add_vehicle(indexer, airplane_cb, 200, 200, 8000, air_cb, vehicle_cb);
+ S_add_vehicle(indexer, bike_cb, 15, 15, 25, land_cb, vehicle_cb);
+ S_add_vehicle(indexer, car_cb, 70, 70, 3000, land_cb, vehicle_cb);
+
+ // Add random objects.
+ VArray *random_strings =
+ S_add_random_objects(&indexer, schema, folder, S_random_string,
+ NULL, random_cb);
+ VArray *random_int32s =
+ S_add_random_objects(&indexer, schema, folder, S_random_int32,
+ int32_cb, random_int32s_cb);
+ VArray *random_int64s =
+ S_add_random_objects(&indexer, schema, folder, S_random_int64,
+ int64_cb, random_int64s_cb);
+ VArray *random_float32s =
+ S_add_random_objects(&indexer, schema, folder, S_random_float32,
+ float32_cb, random_float32s_cb);
+ VArray *random_float64s =
+ S_add_random_objects(&indexer, schema, folder, S_random_float64,
+ float64_cb, random_float64s_cb);
+
+ // Add numbers to verify consistent ordering.
+ int32_t *nums = (int32_t*)MALLOCATE(100 * sizeof(int32_t));
+ for (int i = 0; i < 100; ++i) {
+ nums[i] = i;
+ }
+ // Shuffle
+ for (int i = 99; i > 0; --i) {
+ int r = rand() % (i + 1);
+ if (r != i) {
+ // Swap
+ int32_t tmp = nums[i];
+ nums[i] = nums[r];
+ nums[r] = tmp;
+ }
+ }
+ for (int i = 0; i < 100; ++i) {
+ char name_buf[3];
+ sprintf(name_buf, "%02d", nums[i]);
+ ZombieCharBuf *name = ZCB_WRAP_STR(name_buf, 2);
+ S_add_doc(indexer, (Obj*)name, num_cb, NULL);
+ if (i % 10 == 0) {
+ S_refresh_indexer(&indexer, schema, folder);
+ }
+ }
+ FREEMEM(nums);
+
+ Indexer_Commit(indexer);
+ DECREF(indexer);
+
+ // Start tests
+
+ IndexSearcher *searcher = IxSearcher_new((Obj*)folder);
+
+ results = S_test_sorted_search(searcher, vehicle_cb, 100,
+ name_cb, false, NULL);
+ VA_Clear(wanted);
+ VA_Push(wanted, INCREF(airplane_cb));
+ VA_Push(wanted, INCREF(bike_cb));
+ VA_Push(wanted, INCREF(car_cb));
+ TEST_TRUE(batch, VA_Equals(results, (Obj*)wanted), "sort by one criteria");
+ DECREF(results);
+
+#ifdef LUCY_VALGRIND
+ SKIP(batch, "known leaks");
+ SKIP(batch, "known leaks");
+#else
+ Err *error;
+ SortContext sort_ctx;
+ sort_ctx.searcher = searcher;
+
+ sort_ctx.sort_field = nope_cb;
+ error = Err_trap(S_attempt_sorted_search, &sort_ctx);
+ TEST_TRUE(batch, error != NULL
+ && Err_Is_A(error, ERR)
+ && CB_Find_Str(Err_Get_Mess(error), "sortable", 8) != -1,
+ "sorting on a non-sortable field throws an error");
+ DECREF(error);
+
+ sort_ctx.sort_field = unknown_cb;
+ error = Err_trap(S_attempt_sorted_search, &sort_ctx);
+ TEST_TRUE(batch, error != NULL
+ && Err_Is_A(error, ERR)
+ && CB_Find_Str(Err_Get_Mess(error), "sortable", 8) != -1,
+ "sorting on an unknown field throws an error");
+ DECREF(error);
+#endif
+
+ results = S_test_sorted_search(searcher, vehicle_cb, 100,
+ weight_cb, false, NULL);
+ VA_Clear(wanted);
+ VA_Push(wanted, INCREF(bike_cb));
+ VA_Push(wanted, INCREF(car_cb));
+ VA_Push(wanted, INCREF(airplane_cb));
+ CharBuf *tmp = (CharBuf*)VA_Fetch(results, 0);
+ TEST_TRUE(batch, VA_Equals(results, (Obj*)wanted), "sort by one criteria");
+ DECREF(results);
+
+ results = S_test_sorted_search(searcher, vehicle_cb, 100,
+ name_cb, true, NULL);
+ VA_Clear(wanted);
+ VA_Push(wanted, INCREF(car_cb));
+ VA_Push(wanted, INCREF(bike_cb));
+ VA_Push(wanted, INCREF(airplane_cb));
+ TEST_TRUE(batch, VA_Equals(results, (Obj*)wanted), "reverse sort");
+ DECREF(results);
+
+ results = S_test_sorted_search(searcher, vehicle_cb, 100,
+ home_cb, false, name_cb, false, NULL);
+ VA_Clear(wanted);
+ VA_Push(wanted, INCREF(airplane_cb));
+ VA_Push(wanted, INCREF(bike_cb));
+ VA_Push(wanted, INCREF(car_cb));
+ TEST_TRUE(batch, VA_Equals(results, (Obj*)wanted), "multiple criteria");
+ DECREF(results);
+
+ results = S_test_sorted_search(searcher, vehicle_cb, 100,
+ home_cb, false, name_cb, true, NULL);
+ VA_Clear(wanted);
+ VA_Push(wanted, INCREF(airplane_cb));
+ VA_Push(wanted, INCREF(car_cb));
+ VA_Push(wanted, INCREF(bike_cb));
+ TEST_TRUE(batch, VA_Equals(results, (Obj*)wanted),
+ "multiple criteria with reverse");
+ DECREF(results);
+
+ results = S_test_sorted_search(searcher, vehicle_cb, 100,
+ speed_cb, true, NULL);
+ results2 = S_test_sorted_search(searcher, vehicle_cb, 100,
+ sloth_cb, false, NULL);
+ TEST_TRUE(batch, VA_Equals(results, (Obj*)results2),
+ "FieldType_Compare_Values");
+ DECREF(results2);
+ DECREF(results);
+
+ results = S_test_sorted_search(searcher, random_cb, 100,
+ name_cb, false, NULL);
+ TEST_TRUE(batch, VA_Equals(results, (Obj*)random_strings),
+ "random strings");
+ DECREF(results);
+
+ results = S_test_sorted_search(searcher, random_int32s_cb, 100,
+ int32_cb, false, NULL);
+ TEST_TRUE(batch, VA_Equals(results, (Obj*)random_int32s),
+ "int32");
+ DECREF(results);
+
+ results = S_test_sorted_search(searcher, random_int64s_cb, 100,
+ int64_cb, false, NULL);
+ TEST_TRUE(batch, VA_Equals(results, (Obj*)random_int64s),
+ "int64");
+ DECREF(results);
+
+ results = S_test_sorted_search(searcher, random_float32s_cb, 100,
+ float32_cb, false, NULL);
+ TEST_TRUE(batch, VA_Equals(results, (Obj*)random_float32s),
+ "float32");
+ DECREF(results);
+
+ results = S_test_sorted_search(searcher, random_float64s_cb, 100,
+ float64_cb, false, NULL);
+ TEST_TRUE(batch, VA_Equals(results, (Obj*)random_float64s),
+ "float64");
+ DECREF(results);
+
+ CharBuf *bbbcca_cb = CB_newf("bike bike bike car car airplane");
+ results = S_test_sorted_search(searcher, bbbcca_cb, 100,
+ unused_cb, false, NULL);
+ VA_Clear(wanted);
+ VA_Push(wanted, INCREF(airplane_cb));
+ VA_Push(wanted, INCREF(bike_cb));
+ VA_Push(wanted, INCREF(car_cb));
+ TEST_TRUE(batch, VA_Equals(results, (Obj*)wanted),
+ "sorting on field with no values sorts by doc id");
+ DECREF(results);
+ DECREF(bbbcca_cb);
+
+ CharBuf *nn_cb = CB_newf("99");
+ CharBuf *nn_or_car_cb = CB_newf("99 OR car");
+ results = S_test_sorted_search(searcher, nn_or_car_cb, 10,
+ speed_cb, false, NULL);
+ VA_Clear(wanted);
+ VA_Push(wanted, INCREF(car_cb));
+ VA_Push(wanted, INCREF(nn_cb));
+ TEST_TRUE(batch, VA_Equals(results, (Obj*)wanted),
+ "doc with NULL value sorts last");
+ DECREF(results);
+ DECREF(nn_cb);
+ DECREF(nn_or_car_cb);
+
+ results = S_test_sorted_search(searcher, num_cb, 10,
+ name_cb, false, NULL);
+ results2 = S_test_sorted_search(searcher, num_cb, 30,
+ name_cb, false, NULL);
+ VA_Resize(results2, 10);
+ TEST_TRUE(batch, VA_Equals(results, (Obj*)results2),
+ "same order regardless of queue size");
+ DECREF(results2);
+ DECREF(results);
+
+ results = S_test_sorted_search(searcher, num_cb, 10,
+ name_cb, true, NULL);
+ results2 = S_test_sorted_search(searcher, num_cb, 30,
+ name_cb, true, NULL);
+ VA_Resize(results2, 10);
+ TEST_TRUE(batch, VA_Equals(results, (Obj*)results2),
+ "same order regardless of queue size (reverse sort)");
+ DECREF(results2);
+ DECREF(results);
+
+ DECREF(searcher);
+
+ // Add another seg to index.
+ indexer = Indexer_new(schema, (Obj*)folder, NULL, 0);
+ S_add_vehicle(indexer, carrot_cb, 0, 0, 1, land_cb, food_cb);
+ Indexer_Commit(indexer);
+ DECREF(indexer);
+
+ searcher = IxSearcher_new((Obj*)folder);
+ results = S_test_sorted_search(searcher, vehicle_cb, 100,
+ name_cb, false, NULL);
+ VA_Clear(wanted);
+ VA_Push(wanted, INCREF(airplane_cb));
+ VA_Push(wanted, INCREF(bike_cb));
+ VA_Push(wanted, INCREF(car_cb));
+ TEST_TRUE(batch, VA_Equals(results, (Obj*)wanted), "Multi-segment sort");
+ DECREF(results);
+ DECREF(searcher);
+
+ DECREF(random_strings);
+ DECREF(random_int32s);
+ DECREF(random_int64s);
+ DECREF(random_float32s);
+ DECREF(random_float64s);
+
+ DECREF(wanted);
+ DECREF(schema);
+ DECREF(folder);
+}
+
+void
+TestSortSpec_run_tests() {
+ TestBatch *batch = TestBatch_new(18);
+ TestBatch_Plan(batch);
+ S_init_strings();
+ test_sort_spec(batch);
+ S_destroy_strings();
+ DECREF(batch);
+}
+
+
Added: lucy/trunk/core/Lucy/Test/Search/TestSortSpec.cfh
URL:
http://svn.apache.org/viewvc/lucy/trunk/core/Lucy/Test/Search/TestSortSpec.cfh?rev=1339618&view=auto
==============================================================================
--- lucy/trunk/core/Lucy/Test/Search/TestSortSpec.cfh (added)
+++ lucy/trunk/core/Lucy/Test/Search/TestSortSpec.cfh Thu May 17 14:41:22 2012
@@ -0,0 +1,38 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+parcel Lucy;
+
+inert class Lucy::Test::Search::TestSortSpec {
+ inert void
+ run_tests();
+}
+
+class Lucy::Test::Search::TestReverseType inherits Lucy::Plan::Int32Type {
+ public inert TestReverseType*
+ new();
+
+ public inert TestReverseType*
+ init(TestReverseType *self);
+
+ inert TestReverseType*
+ init2(TestReverseType *self, float boost = 1.0, bool_t indexed = true,
+ bool_t stored = true, bool_t sortable = false);
+
+ public int32_t
+ Compare_Values(TestReverseType *self, Obj *a, Obj *b);
+}
+
Modified: lucy/trunk/perl/buildlib/Lucy/Build/Binding/Misc.pm
URL:
http://svn.apache.org/viewvc/lucy/trunk/perl/buildlib/Lucy/Build/Binding/Misc.pm?rev=1339618&r1=1339617&r2=1339618&view=diff
==============================================================================
--- lucy/trunk/perl/buildlib/Lucy/Build/Binding/Misc.pm (original)
+++ lucy/trunk/perl/buildlib/Lucy/Build/Binding/Misc.pm Thu May 17 14:41:22 2012
@@ -198,18 +198,21 @@ PPCODE:
else if (strEQ(package, "TestQueryParserLogic")) {
lucy_TestQPLogic_run_tests();
}
- else if (strEQ(package, "TestSeriesMatcher")) {
- lucy_TestSeriesMatcher_run_tests();
- }
- else if (strEQ(package, "TestSpan")) {
- lucy_TestSpan_run_tests();
- }
else if (strEQ(package, "TestRangeQuery")) {
lucy_TestRangeQuery_run_tests();
}
else if (strEQ(package, "TestReqOptQuery")) {
lucy_TestReqOptQuery_run_tests();
}
+ else if (strEQ(package, "TestSeriesMatcher")) {
+ lucy_TestSeriesMatcher_run_tests();
+ }
+ else if (strEQ(package, "TestSortSpec")) {
+ lucy_TestSortSpec_run_tests();
+ }
+ else if (strEQ(package, "TestSpan")) {
+ lucy_TestSpan_run_tests();
+ }
else if (strEQ(package, "TestTermQuery")) {
lucy_TestTermQuery_run_tests();
}
Added: lucy/trunk/perl/t/binding/511-sort_spec.t
URL:
http://svn.apache.org/viewvc/lucy/trunk/perl/t/binding/511-sort_spec.t?rev=1339618&view=auto
==============================================================================
--- lucy/trunk/perl/t/binding/511-sort_spec.t (added)
+++ lucy/trunk/perl/t/binding/511-sort_spec.t Thu May 17 14:41:22 2012
@@ -0,0 +1,160 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+use strict;
+use warnings;
+
+use Test::More tests => 7;
+
+package ReverseType;
+use base qw( Lucy::Plan::Int32Type );
+
+sub new {
+ return shift->SUPER::new( indexed => 0, sortable => 1, @_ );
+}
+
+sub compare_values {
+ my ( $self, %args ) = @_;
+ return $args{b} <=> $args{a};
+}
+
+package main;
+use Lucy::Test;
+
+my $schema = Lucy::Plan::Schema->new;
+
+my $unsortable = Lucy::Plan::FullTextType->new(
+ analyzer => Lucy::Analysis::StandardTokenizer->new
+);
+my $string_type = Lucy::Plan::StringType->new( sortable => 1 );
+my $int32_type = Lucy::Plan::Int32Type->new(
+ indexed => 0,
+ sortable => 1,
+);
+
+$schema->spec_field( name => 'name', type => $string_type );
+$schema->spec_field( name => 'speed', type => $int32_type );
+$schema->spec_field( name => 'sloth', type => ReverseType->new );
+$schema->spec_field( name => 'weight', type => $int32_type );
+$schema->spec_field( name => 'home', type => $string_type );
+$schema->spec_field( name => 'cat', type => $string_type );
+$schema->spec_field( name => 'nope', type => $unsortable );
+
+my $airplane = {
+ name => 'airplane',
+ speed => 200,
+ sloth => 200,
+ weight => 8000,
+ home => 'air',
+ cat => 'vehicle',
+};
+my $bike = {
+ name => 'bike',
+ speed => 15,
+ sloth => 15,
+ weight => 25,
+ home => 'land',
+ cat => 'vehicle',
+};
+my $car = {
+ name => 'car',
+ speed => 70,
+ sloth => 70,
+ weight => 3000,
+ home => 'land',
+ cat => 'vehicle',
+};
+
+my $folder = Lucy::Store::RAMFolder->new;
+my $indexer = Lucy::Index::Indexer->new(
+ index => $folder,
+ schema => $schema,
+);
+
+# First, add vehicles.
+$indexer->add_doc($_) for ( $airplane, $bike, $car );
+
+# Add random strings.
+my @random_strings;
+my @letters = 'a' .. 'z';
+for ( 0 .. 99 ) {
+ my $string = "";
+ for ( 0 .. int( rand(10) ) ) {
+ $string .= $letters[ rand @letters ];
+ }
+ $indexer->add_doc(
+ { cat => 'random',
+ name => $string,
+ }
+ );
+ push @random_strings, $string;
+}
+@random_strings = sort @random_strings;
+
+$indexer->commit;
+my $searcher = Lucy::Search::IndexSearcher->new( index => $folder );
+
+my $results = test_sorted_search( 'vehicle', 100, name => 0 );
+is_deeply( $results, [qw( airplane bike car )], "sort by one criteria" );
+
+$results = test_sorted_search( 'vehicle', 100, weight => 0 );
+is_deeply( $results, [qw( bike car airplane )], "sort by one criteria" );
+
+$results = test_sorted_search( 'vehicle', 100, name => 1 );
+is_deeply( $results, [qw( car bike airplane )], "reverse sort" );
+
+$results = test_sorted_search( 'vehicle', 100, home => 0, name => 0 );
+is_deeply( $results, [qw( airplane bike car )], "multiple criteria" );
+
+$results = test_sorted_search( 'vehicle', 100, home => 0, name => 1 );
+is_deeply( $results, [qw( airplane car bike )],
+ "multiple criteria with reverse" );
+
+$results = test_sorted_search( 'vehicle', 100, speed => 1 );
+my $reversed = test_sorted_search( 'vehicle', 100, sloth => 0 );
+is_deeply( $results, $reversed, "FieldType_Compare_Values" );
+
+$results = test_sorted_search( 'random', 100, name => 0, );
+is_deeply( $results, \@random_strings, "random strings" );
+
+# Take a list of criteria, create a SortSpec, perform a search, and return an
+# Array of 'name' values for the sorted results.
+sub test_sorted_search {
+ my ( $query, $num_wanted, @criteria ) = @_;
+ my @rules;
+
+ while (@criteria) {
+ my $field = shift @criteria;
+ my $rev = shift @criteria;
+ push @rules,
+ Lucy::Search::SortRule->new(
+ field => $field,
+ reverse => $rev,
+ );
+ }
+ push @rules, Lucy::Search::SortRule->new( type => 'doc_id' );
+ my $sort_spec = Lucy::Search::SortSpec->new( rules => \@rules );
+ my $hits = $searcher->hits(
+ query => $query,
+ sort_spec => $sort_spec,
+ num_wanted => $num_wanted,
+ );
+ my @results;
+ while ( my $hit = $hits->next ) {
+ push @results, $hit->{name};
+ }
+
+ return \@results;
+}
Added: lucy/trunk/perl/t/core/511-sort_spec.t
URL:
http://svn.apache.org/viewvc/lucy/trunk/perl/t/core/511-sort_spec.t?rev=1339618&view=auto
==============================================================================
--- lucy/trunk/perl/t/core/511-sort_spec.t (added)
+++ lucy/trunk/perl/t/core/511-sort_spec.t Thu May 17 14:41:22 2012
@@ -0,0 +1,21 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+use strict;
+use warnings;
+
+use Lucy::Test;
+Lucy::Test::run_tests("TestSortSpec");
+