• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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