1 // Copyright (C) 2024 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "icing/expand/stemming/stemming-expander.h" 16 17 #include <memory> 18 #include <string> 19 #include <string_view> 20 #include <utility> 21 #include <vector> 22 23 #include "icing/text_classifier/lib3/utils/base/statusor.h" 24 #include "icing/absl_ports/mutex.h" 25 #include "icing/expand/expander.h" 26 #include "icing/expand/stemming/stemmer-factory.h" 27 #include "icing/expand/stemming/stemmer.h" 28 #include "icing/util/status-macros.h" 29 30 namespace icing { 31 namespace lib { 32 33 /*static*/ libtextclassifier3::StatusOr<std::unique_ptr<StemmingExpander>> Create(std::string language_code)34StemmingExpander::Create(std::string language_code) { 35 ICING_ASSIGN_OR_RETURN(std::unique_ptr<Stemmer> stemmer, 36 stemmer_factory::Create(language_code)); 37 38 return std::unique_ptr<StemmingExpander>( 39 new StemmingExpander(std::move(language_code), std::move(stemmer))); 40 } 41 Expand(std::string_view term) const42std::vector<ExpandedTerm> StemmingExpander::Expand( 43 std::string_view term) const { 44 std::vector<ExpandedTerm> result; 45 // Add the original term. 46 result.emplace_back(std::string(term), /*is_stemmed_term=*/false); 47 48 libtextclassifier3::StatusOr<std::unique_ptr<Stemmer>> stemmer_or = 49 ProduceStemmer(); 50 if (!stemmer_or.ok()) { 51 return result; 52 } 53 54 std::unique_ptr<Stemmer> stemmer = std::move(stemmer_or).ValueOrDie(); 55 std::string stemmed_term = stemmer->Stem(term); 56 ReturnStemmer(std::move(stemmer)); 57 58 if (stemmed_term != term) { 59 result.emplace_back(std::move(stemmed_term), /*is_stemmed_term=*/true); 60 } 61 return result; 62 } 63 64 libtextclassifier3::StatusOr<std::unique_ptr<Stemmer>> ProduceStemmer() const65StemmingExpander::ProduceStemmer() const { 66 std::unique_ptr<Stemmer> stemmer = nullptr; 67 { 68 absl_ports::unique_lock l(&mutex_); 69 if (cached_stemmer_ != nullptr) { 70 stemmer = std::move(cached_stemmer_); 71 } 72 } 73 if (stemmer == nullptr) { 74 ICING_ASSIGN_OR_RETURN(stemmer, stemmer_factory::Create(language_code_)); 75 } 76 77 return stemmer; 78 } 79 ReturnStemmer(std::unique_ptr<Stemmer> stemmer) const80void StemmingExpander::ReturnStemmer(std::unique_ptr<Stemmer> stemmer) const { 81 absl_ports::unique_lock l(&mutex_); 82 if (!cached_stemmer_) { 83 cached_stemmer_ = std::move(stemmer); 84 } 85 } 86 87 } // namespace lib 88 } // namespace icing 89