1 // Copyright (C) 2022 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 #ifndef ICING_SCORING_ADVANCED_SCORING_SCORE_EXPRESSION_H_ 16 #define ICING_SCORING_ADVANCED_SCORING_SCORE_EXPRESSION_H_ 17 18 #include <algorithm> 19 #include <cmath> 20 #include <memory> 21 #include <unordered_map> 22 #include <unordered_set> 23 #include <vector> 24 25 #include "icing/text_classifier/lib3/utils/base/statusor.h" 26 #include "icing/index/hit/doc-hit-info.h" 27 #include "icing/index/iterator/doc-hit-info-iterator.h" 28 #include "icing/join/join-children-fetcher.h" 29 #include "icing/scoring/bm25f-calculator.h" 30 #include "icing/store/document-store.h" 31 #include "icing/util/status-macros.h" 32 33 namespace icing { 34 namespace lib { 35 36 enum class ScoreExpressionType { 37 kDouble, 38 kDoubleList, 39 kDocument // Only "this" is considered as document type. 40 }; 41 42 class ScoreExpression { 43 public: 44 virtual ~ScoreExpression() = default; 45 46 // Evaluate the score expression to double with the current document. 47 // 48 // RETURNS: 49 // - The evaluated result as a double on success. 50 // - INVALID_ARGUMENT if a non-finite value is reached while evaluating the 51 // expression. 52 // - INTERNAL if there are inconsistencies. eval(const DocHitInfo & hit_info,const DocHitInfoIterator * query_it)53 virtual libtextclassifier3::StatusOr<double> eval( 54 const DocHitInfo& hit_info, const DocHitInfoIterator* query_it) const { 55 if (type() == ScoreExpressionType::kDouble) { 56 return absl_ports::UnimplementedError( 57 "All ScoreExpressions of type Double must provide their own " 58 "implementation of eval!"); 59 } 60 return absl_ports::InternalError( 61 "Runtime type error: the expression should never be evaluated to a " 62 "double. There must be inconsistencies in the static type checking."); 63 } 64 eval_list(const DocHitInfo & hit_info,const DocHitInfoIterator * query_it)65 virtual libtextclassifier3::StatusOr<std::vector<double>> eval_list( 66 const DocHitInfo& hit_info, const DocHitInfoIterator* query_it) const { 67 if (type() == ScoreExpressionType::kDoubleList) { 68 return absl_ports::UnimplementedError( 69 "All ScoreExpressions of type Double List must provide their own " 70 "implementation of eval_list!"); 71 } 72 return absl_ports::InternalError( 73 "Runtime type error: the expression should never be evaluated to a " 74 "double list. There must be inconsistencies in the static type " 75 "checking."); 76 } 77 78 // Indicate the type to which the current expression will be evaluated. 79 virtual ScoreExpressionType type() const = 0; 80 81 // Indicate whether the current expression is a constant double. 82 // Returns true if and only if the object is of ConstantScoreExpression type. is_constant_double()83 virtual bool is_constant_double() const { return false; } 84 }; 85 86 class ThisExpression : public ScoreExpression { 87 public: Create()88 static std::unique_ptr<ThisExpression> Create() { 89 return std::unique_ptr<ThisExpression>(new ThisExpression()); 90 } 91 type()92 ScoreExpressionType type() const override { 93 return ScoreExpressionType::kDocument; 94 } 95 96 private: 97 ThisExpression() = default; 98 }; 99 100 class ConstantScoreExpression : public ScoreExpression { 101 public: Create(libtextclassifier3::StatusOr<double> c)102 static std::unique_ptr<ConstantScoreExpression> Create( 103 libtextclassifier3::StatusOr<double> c) { 104 return std::unique_ptr<ConstantScoreExpression>( 105 new ConstantScoreExpression(c)); 106 } 107 eval(const DocHitInfo &,const DocHitInfoIterator *)108 libtextclassifier3::StatusOr<double> eval( 109 const DocHitInfo&, const DocHitInfoIterator*) const override { 110 return c_; 111 } 112 type()113 ScoreExpressionType type() const override { 114 return ScoreExpressionType::kDouble; 115 } 116 is_constant_double()117 bool is_constant_double() const override { return true; } 118 119 private: ConstantScoreExpression(libtextclassifier3::StatusOr<double> c)120 explicit ConstantScoreExpression(libtextclassifier3::StatusOr<double> c) 121 : c_(c) {} 122 123 libtextclassifier3::StatusOr<double> c_; 124 }; 125 126 class OperatorScoreExpression : public ScoreExpression { 127 public: 128 enum class OperatorType { kPlus, kMinus, kNegative, kTimes, kDiv }; 129 130 // RETURNS: 131 // - An OperatorScoreExpression instance on success if not simplifiable. 132 // - A ConstantScoreExpression instance on success if simplifiable. 133 // - FAILED_PRECONDITION on any null pointer in children. 134 // - INVALID_ARGUMENT on type errors. 135 static libtextclassifier3::StatusOr<std::unique_ptr<ScoreExpression>> Create( 136 OperatorType op, std::vector<std::unique_ptr<ScoreExpression>> children); 137 138 libtextclassifier3::StatusOr<double> eval( 139 const DocHitInfo& hit_info, 140 const DocHitInfoIterator* query_it) const override; 141 type()142 ScoreExpressionType type() const override { 143 return ScoreExpressionType::kDouble; 144 } 145 146 private: OperatorScoreExpression(OperatorType op,std::vector<std::unique_ptr<ScoreExpression>> children)147 explicit OperatorScoreExpression( 148 OperatorType op, std::vector<std::unique_ptr<ScoreExpression>> children) 149 : op_(op), children_(std::move(children)) {} 150 151 OperatorType op_; 152 std::vector<std::unique_ptr<ScoreExpression>> children_; 153 }; 154 155 class MathFunctionScoreExpression : public ScoreExpression { 156 public: 157 enum class FunctionType { 158 kLog, 159 kPow, 160 kMax, 161 kMin, 162 kLen, 163 kSum, 164 kAvg, 165 kSqrt, 166 kAbs, 167 kSin, 168 kCos, 169 kTan 170 }; 171 172 static const std::unordered_map<std::string, FunctionType> kFunctionNames; 173 174 static const std::unordered_set<FunctionType> kVariableArgumentsFunctions; 175 176 // RETURNS: 177 // - A MathFunctionScoreExpression instance on success if not simplifiable. 178 // - A ConstantScoreExpression instance on success if simplifiable. 179 // - FAILED_PRECONDITION on any null pointer in args. 180 // - INVALID_ARGUMENT on type errors. 181 static libtextclassifier3::StatusOr<std::unique_ptr<ScoreExpression>> Create( 182 FunctionType function_type, 183 std::vector<std::unique_ptr<ScoreExpression>> args); 184 185 libtextclassifier3::StatusOr<double> eval( 186 const DocHitInfo& hit_info, 187 const DocHitInfoIterator* query_it) const override; 188 type()189 ScoreExpressionType type() const override { 190 return ScoreExpressionType::kDouble; 191 } 192 193 private: MathFunctionScoreExpression(FunctionType function_type,std::vector<std::unique_ptr<ScoreExpression>> args)194 explicit MathFunctionScoreExpression( 195 FunctionType function_type, 196 std::vector<std::unique_ptr<ScoreExpression>> args) 197 : function_type_(function_type), args_(std::move(args)) {} 198 199 FunctionType function_type_; 200 std::vector<std::unique_ptr<ScoreExpression>> args_; 201 }; 202 203 class DocumentFunctionScoreExpression : public ScoreExpression { 204 public: 205 enum class FunctionType { 206 kDocumentScore, 207 kCreationTimestamp, 208 kUsageCount, 209 kUsageLastUsedTimestamp, 210 }; 211 212 static const std::unordered_map<std::string, FunctionType> kFunctionNames; 213 214 // RETURNS: 215 // - A DocumentFunctionScoreExpression instance on success. 216 // - FAILED_PRECONDITION on any null pointer in args. 217 // - INVALID_ARGUMENT on type errors. 218 static libtextclassifier3::StatusOr< 219 std::unique_ptr<DocumentFunctionScoreExpression>> 220 Create(FunctionType function_type, 221 std::vector<std::unique_ptr<ScoreExpression>> args, 222 const DocumentStore* document_store, double default_score, 223 int64_t current_time_ms); 224 225 libtextclassifier3::StatusOr<double> eval( 226 const DocHitInfo& hit_info, 227 const DocHitInfoIterator* query_it) const override; 228 type()229 ScoreExpressionType type() const override { 230 return ScoreExpressionType::kDouble; 231 } 232 233 private: DocumentFunctionScoreExpression(FunctionType function_type,std::vector<std::unique_ptr<ScoreExpression>> args,const DocumentStore * document_store,double default_score,int64_t current_time_ms)234 explicit DocumentFunctionScoreExpression( 235 FunctionType function_type, 236 std::vector<std::unique_ptr<ScoreExpression>> args, 237 const DocumentStore* document_store, double default_score, 238 int64_t current_time_ms) 239 : args_(std::move(args)), 240 document_store_(*document_store), 241 default_score_(default_score), 242 function_type_(function_type), 243 current_time_ms_(current_time_ms) {} 244 245 std::vector<std::unique_ptr<ScoreExpression>> args_; 246 const DocumentStore& document_store_; 247 double default_score_; 248 FunctionType function_type_; 249 int64_t current_time_ms_; 250 }; 251 252 class RelevanceScoreFunctionScoreExpression : public ScoreExpression { 253 public: 254 static constexpr std::string_view kFunctionName = "relevanceScore"; 255 256 // RETURNS: 257 // - A RelevanceScoreFunctionScoreExpression instance on success. 258 // - FAILED_PRECONDITION on any null pointer in args. 259 // - INVALID_ARGUMENT on type errors. 260 static libtextclassifier3::StatusOr< 261 std::unique_ptr<RelevanceScoreFunctionScoreExpression>> 262 Create(std::vector<std::unique_ptr<ScoreExpression>> args, 263 Bm25fCalculator* bm25f_calculator, double default_score); 264 265 libtextclassifier3::StatusOr<double> eval( 266 const DocHitInfo& hit_info, 267 const DocHitInfoIterator* query_it) const override; 268 type()269 ScoreExpressionType type() const override { 270 return ScoreExpressionType::kDouble; 271 } 272 273 private: RelevanceScoreFunctionScoreExpression(Bm25fCalculator * bm25f_calculator,double default_score)274 explicit RelevanceScoreFunctionScoreExpression( 275 Bm25fCalculator* bm25f_calculator, double default_score) 276 : bm25f_calculator_(*bm25f_calculator), default_score_(default_score) {} 277 278 Bm25fCalculator& bm25f_calculator_; 279 double default_score_; 280 }; 281 282 class ChildrenRankingSignalsFunctionScoreExpression : public ScoreExpression { 283 public: 284 static constexpr std::string_view kFunctionName = "childrenRankingSignals"; 285 286 // RETURNS: 287 // - A ChildrenRankingSignalsFunctionScoreExpression instance on success. 288 // - FAILED_PRECONDITION on any null pointer in children. 289 // - INVALID_ARGUMENT on type errors. 290 static libtextclassifier3::StatusOr< 291 std::unique_ptr<ChildrenRankingSignalsFunctionScoreExpression>> 292 Create(std::vector<std::unique_ptr<ScoreExpression>> args, 293 const JoinChildrenFetcher* join_children_fetcher); 294 295 libtextclassifier3::StatusOr<std::vector<double>> eval_list( 296 const DocHitInfo& hit_info, 297 const DocHitInfoIterator* query_it) const override; 298 type()299 ScoreExpressionType type() const override { 300 return ScoreExpressionType::kDoubleList; 301 } 302 303 private: ChildrenRankingSignalsFunctionScoreExpression(const JoinChildrenFetcher & join_children_fetcher)304 explicit ChildrenRankingSignalsFunctionScoreExpression( 305 const JoinChildrenFetcher& join_children_fetcher) 306 : join_children_fetcher_(join_children_fetcher) {} 307 const JoinChildrenFetcher& join_children_fetcher_; 308 }; 309 310 class PropertyWeightsFunctionScoreExpression : public ScoreExpression { 311 public: 312 static constexpr std::string_view kFunctionName = "propertyWeights"; 313 314 // RETURNS: 315 // - A PropertyWeightsFunctionScoreExpression instance on success. 316 // - FAILED_PRECONDITION on any null pointer in children. 317 // - INVALID_ARGUMENT on type errors. 318 static libtextclassifier3::StatusOr< 319 std::unique_ptr<PropertyWeightsFunctionScoreExpression>> 320 Create(std::vector<std::unique_ptr<ScoreExpression>> args, 321 const DocumentStore* document_store, 322 const SectionWeights* section_weights, int64_t current_time_ms); 323 324 libtextclassifier3::StatusOr<std::vector<double>> eval_list( 325 const DocHitInfo& hit_info, const DocHitInfoIterator*) const override; 326 type()327 ScoreExpressionType type() const override { 328 return ScoreExpressionType::kDoubleList; 329 } 330 331 SchemaTypeId GetSchemaTypeId(DocumentId document_id) const; 332 333 private: PropertyWeightsFunctionScoreExpression(const DocumentStore * document_store,const SectionWeights * section_weights,int64_t current_time_ms)334 explicit PropertyWeightsFunctionScoreExpression( 335 const DocumentStore* document_store, 336 const SectionWeights* section_weights, int64_t current_time_ms) 337 : document_store_(*document_store), 338 section_weights_(*section_weights), 339 current_time_ms_(current_time_ms) {} 340 const DocumentStore& document_store_; 341 const SectionWeights& section_weights_; 342 int64_t current_time_ms_; 343 }; 344 345 } // namespace lib 346 } // namespace icing 347 348 #endif // ICING_SCORING_ADVANCED_SCORING_SCORE_EXPRESSION_H_ 349