diff options
author | Tim Barron <tjbarron@google.com> | 2023-03-31 16:48:52 -0700 |
---|---|---|
committer | Tim Barron <tjbarron@google.com> | 2023-03-31 16:48:52 -0700 |
commit | b59049b030cc330b6c8ae1d03ea4c1a34235ac9b (patch) | |
tree | 09bb4692739de390a5ad70e5dc4f9acb7830fa3e /icing/query/advanced_query_parser | |
parent | f3155ae11285c16d8d9de56b1ec1a1e0def2cf62 (diff) | |
download | icing-b59049b030cc330b6c8ae1d03ea4c1a34235ac9b.tar.gz |
Update Icing from upstream.
Descriptions:
========================================================================
Make int64_t the CreateUsageReport timestamp type
========================================================================
Create ResultAdjustmentInfo and refactor ResultStateV2
========================================================================
Wrap parent/child adjustment info to std::unique_ptr
========================================================================
Apply join child snippet
========================================================================
Apply join child projection
========================================================================
Add IntegerSectionIndexingHandlerTest
========================================================================
Delete Result Retriever this class is dead code.
========================================================================
Introduce a placeholder for the custom function hasPropertyDefined(member)
========================================================================
Fix libtextclassifier3::StatusOr
========================================================================
Performance improvements to SnippetRetriever.
========================================================================
Bug: 193244409
Bug: 256022027
Bug: 259744228
Bug: 268680462
Bug: 270102295
Bug: 271015984
Bug: 274627497
Change-Id: I6bad316b28bb289fa8e3f5b0982d6aaa9e0d135f
Diffstat (limited to 'icing/query/advanced_query_parser')
-rw-r--r-- | icing/query/advanced_query_parser/query-visitor.cc | 36 | ||||
-rw-r--r-- | icing/query/advanced_query_parser/query-visitor.h | 7 | ||||
-rw-r--r-- | icing/query/advanced_query_parser/query-visitor_test.cc | 119 |
3 files changed, 160 insertions, 2 deletions
diff --git a/icing/query/advanced_query_parser/query-visitor.cc b/icing/query/advanced_query_parser/query-visitor.cc index 31223a5..c2cee47 100644 --- a/icing/query/advanced_query_parser/query-visitor.cc +++ b/icing/query/advanced_query_parser/query-visitor.cc @@ -28,6 +28,7 @@ #include "icing/text_classifier/lib3/utils/base/statusor.h" #include "icing/absl_ports/canonical_errors.h" #include "icing/absl_ports/str_cat.h" +#include "icing/index/iterator/doc-hit-info-iterator-all-document-id.h" #include "icing/index/iterator/doc-hit-info-iterator-and.h" #include "icing/index/iterator/doc-hit-info-iterator-none.h" #include "icing/index/iterator/doc-hit-info-iterator-not.h" @@ -204,8 +205,9 @@ void QueryVisitor::RegisterFunctions() { // DocHitInfoIterator search(std::string); // DocHitInfoIterator search(std::string, std::vector<std::string>); - Function::EvalFunction search_eval = - std::bind(&QueryVisitor::SearchFunction, this, std::placeholders::_1); + auto search_eval = [this](std::vector<PendingValue>&& args) { + return this->SearchFunction(std::move(args)); + }; Function search_function = Function::Create(DataType::kDocumentIterator, "search", {Param(DataType::kString), @@ -214,6 +216,18 @@ void QueryVisitor::RegisterFunctions() { .ValueOrDie(); registered_functions_.insert( {search_function.name(), std::move(search_function)}); + + // DocHitInfoIterator propertyDefined(std::string); + auto property_defined = [this](std::vector<PendingValue>&& args) { + return this->PropertyDefinedFunction(std::move(args)); + }; + + Function property_defined_function = + Function::Create(DataType::kDocumentIterator, "propertyDefined", + {Param(DataType::kText)}, std::move(property_defined)) + .ValueOrDie(); + registered_functions_.insert( + {property_defined_function.name(), std::move(property_defined_function)}); } libtextclassifier3::StatusOr<PendingValue> QueryVisitor::SearchFunction( @@ -285,6 +299,24 @@ libtextclassifier3::StatusOr<PendingValue> QueryVisitor::SearchFunction( return PendingValue(std::move(iterator)); } +libtextclassifier3::StatusOr<PendingValue> +QueryVisitor::PropertyDefinedFunction(std::vector<PendingValue>&& args) { + // The first arg is guaranteed to be a TEXT at this point. It should be safe + // to call ValueOrDie. + + // TODO(b/268680462): Consume this and implement the actual iterator. + // const QueryTerm* member = + args.at(0).text_val().ValueOrDie(); + + std::unique_ptr<DocHitInfoIterator> iterator = + std::make_unique<DocHitInfoIteratorAllDocumentId>( + document_store_.last_added_document_id()); + + features_.insert(kPropertyDefinedInSchemaCustomFunctionFeature); + + return PendingValue(std::move(iterator)); +} + libtextclassifier3::StatusOr<int64_t> QueryVisitor::PopPendingIntValue() { if (pending_values_.empty()) { return absl_ports::InvalidArgumentError("Unable to retrieve int value."); diff --git a/icing/query/advanced_query_parser/query-visitor.h b/icing/query/advanced_query_parser/query-visitor.h index 9fcaec0..c5598dd 100644 --- a/icing/query/advanced_query_parser/query-visitor.h +++ b/icing/query/advanced_query_parser/query-visitor.h @@ -242,6 +242,13 @@ class QueryVisitor : public AbstractSyntaxTreeVisitor { libtextclassifier3::StatusOr<PendingValue> SearchFunction( std::vector<PendingValue>&& args); + // Implementation of the propertyDefined(member) custom function. + // Returns: + // - a Pending Value holding a DocHitIterator to be implemented. + // - any errors returned by Lexer::ExtractTokens + libtextclassifier3::StatusOr<PendingValue> PropertyDefinedFunction( + std::vector<PendingValue>&& args); + // Handles a NaryOperatorNode where the operator is HAS (':') and pushes an // iterator with the proper section filter applied. If the current property // restriction represented by pending_property_restricts and the first child diff --git a/icing/query/advanced_query_parser/query-visitor_test.cc b/icing/query/advanced_query_parser/query-visitor_test.cc index b560d52..7aef40f 100644 --- a/icing/query/advanced_query_parser/query-visitor_test.cc +++ b/icing/query/advanced_query_parser/query-visitor_test.cc @@ -3583,6 +3583,125 @@ TEST_F(QueryVisitorTest, SearchFunctionNestedPropertyRestrictsExpanding) { ElementsAre(docid6, docid0)); } +TEST_F(QueryVisitorTest, + PropertyDefinedFunctionWithNoArgumentReturnsInvalidArgument) { + std::string query = "propertyDefined()"; + ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Node> root_node, + ParseQueryHelper(query)); + QueryVisitor query_visitor( + index_.get(), numeric_index_.get(), document_store_.get(), + schema_store_.get(), normalizer_.get(), tokenizer_.get(), query, + DocHitInfoIteratorFilter::Options(), TERM_MATCH_PREFIX, + /*needs_term_frequency_info_=*/true); + root_node->Accept(&query_visitor); + EXPECT_THAT(std::move(query_visitor).ConsumeResults(), + StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT)); +} + +TEST_F( + QueryVisitorTest, + PropertyDefinedFunctionWithMoreThanOneTextArgumentReturnsInvalidArgument) { + std::string query = "propertyDefined(foo, bar)"; + ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Node> root_node, + ParseQueryHelper(query)); + QueryVisitor query_visitor( + index_.get(), numeric_index_.get(), document_store_.get(), + schema_store_.get(), normalizer_.get(), tokenizer_.get(), query, + DocHitInfoIteratorFilter::Options(), TERM_MATCH_PREFIX, + /*needs_term_frequency_info_=*/true); + root_node->Accept(&query_visitor); + EXPECT_THAT(std::move(query_visitor).ConsumeResults(), + StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT)); +} + +TEST_F(QueryVisitorTest, + PropertyDefinedFunctionWithStringArgumentReturnsInvalidArgument) { + // The argument type is STRING, not TEXT here. + std::string query = "propertyDefined(\"foo\")"; + ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Node> root_node, + ParseQueryHelper(query)); + QueryVisitor query_visitor( + index_.get(), numeric_index_.get(), document_store_.get(), + schema_store_.get(), normalizer_.get(), tokenizer_.get(), query, + DocHitInfoIteratorFilter::Options(), TERM_MATCH_PREFIX, + /*needs_term_frequency_info_=*/true); + root_node->Accept(&query_visitor); + EXPECT_THAT(std::move(query_visitor).ConsumeResults(), + StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT)); +} + +TEST_F(QueryVisitorTest, + PropertyDefinedFunctionWithNonTextArgumentReturnsInvalidArgument) { + std::string query = "propertyDefined(1 < 2)"; + ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Node> root_node, + ParseQueryHelper(query)); + QueryVisitor query_visitor( + index_.get(), numeric_index_.get(), document_store_.get(), + schema_store_.get(), normalizer_.get(), tokenizer_.get(), query, + DocHitInfoIteratorFilter::Options(), TERM_MATCH_PREFIX, + /*needs_term_frequency_info_=*/true); + root_node->Accept(&query_visitor); + EXPECT_THAT(std::move(query_visitor).ConsumeResults(), + StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT)); +} + +TEST_P(QueryVisitorTest, PropertyDefinedFunctionCurrentlyReturnsEverything) { + // Set up two schemas, one with a "url" field and one without. + ICING_ASSERT_OK(schema_store_->SetSchema( + SchemaBuilder() + .AddType(SchemaTypeConfigBuilder() + .SetType("typeWithUrl") + .AddProperty(PropertyConfigBuilder() + .SetName("url") + .SetDataType(TYPE_STRING) + .SetCardinality(CARDINALITY_OPTIONAL))) + .AddType(SchemaTypeConfigBuilder().SetType("typeWithoutUrl")) + .Build())); + + ICING_ASSERT_OK(document_store_->Put( + DocumentBuilder().SetKey("ns", "uri0").SetSchema("typeWithUrl").Build())); + Index::Editor editor = index_->Edit(kDocumentId0, kSectionId1, + TERM_MATCH_PREFIX, /*namespace_id=*/0); + editor.BufferTerm("foo"); + editor.IndexAllBufferedTerms(); + + ICING_ASSERT_OK(document_store_->Put(DocumentBuilder() + .SetKey("ns", "uri1") + .SetSchema("typeWithoutUrl") + .Build())); + editor = index_->Edit(kDocumentId1, kSectionId1, TERM_MATCH_PREFIX, + /*namespace_id=*/0); + editor.BufferTerm("foo"); + editor.IndexAllBufferedTerms(); + + ICING_ASSERT_OK(document_store_->Put( + DocumentBuilder().SetKey("ns", "uri2").SetSchema("typeWithUrl").Build())); + editor = index_->Edit(kDocumentId2, kSectionId1, TERM_MATCH_PREFIX, + /*namespace_id=*/0); + editor.BufferTerm("bar"); + editor.IndexAllBufferedTerms(); + + std::string query = CreateQuery("foo propertyDefined(url)"); + ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Node> root_node, + ParseQueryHelper(query)); + QueryVisitor query_visitor( + index_.get(), numeric_index_.get(), document_store_.get(), + schema_store_.get(), normalizer_.get(), tokenizer_.get(), query, + DocHitInfoIteratorFilter::Options(), TERM_MATCH_PREFIX, + /*needs_term_frequency_info_=*/true); + root_node->Accept(&query_visitor); + ICING_ASSERT_OK_AND_ASSIGN(QueryResults query_results, + std::move(query_visitor).ConsumeResults()); + EXPECT_THAT( + query_results.features_in_use, + UnorderedElementsAre(kPropertyDefinedInSchemaCustomFunctionFeature, + kListFilterQueryLanguageFeature)); + + // TODO(b/268680462): Update once the feature is actually implemented. + EXPECT_THAT(GetDocumentIds(query_results.root_iterator.get()), + UnorderedElementsAre(kDocumentId0, kDocumentId1)); +} + INSTANTIATE_TEST_SUITE_P(QueryVisitorTest, QueryVisitorTest, testing::Values(QueryType::kPlain, QueryType::kSearch)); |