CWIS Developer Documentation
Recommender.php
Go to the documentation of this file.
1 <?PHP
2 
3 #
4 # FILE: SPT--Recommender.php
5 #
6 # Part of the Collection Workflow Integration System (CWIS)
7 # Copyright 2004-2013 Edward Almasy and Internet Scout Research Group
8 # http://scout.wisc.edu/cwis/
9 #
10 
11 class Recommender {
12 
13  # ---- PUBLIC INTERFACE --------------------------------------------------
14  # define content field types
20 
21  # object constructor
25  {
26  # set default parameters
27  $this->ContentCorrelationThreshold = 1;
28 
29  # save database object
30  $this->DB =& $DB;
31 
32  # save new configuration values
33  $this->ItemTableName = $ItemTableName;
34  $this->RatingTableName = $RatingTableName;
35  $this->ItemIdFieldName = $ItemIdFieldName;
36  $this->UserIdFieldName = $UserIdFieldName;
37  $this->RatingFieldName = $RatingFieldName;
38  $this->ContentFields = $ContentFields;
39 
40  # set default debug state
41  $this->DebugLevel = 0;
42  }
43 
44  # set level for debugging output
45  function DebugLevel($Setting)
46  {
47  $this->DebugLevel = $Setting;
48  }
49 
50 
51  # ---- recommendation methods
52 
53  # recommend items for specified user
54  function Recommend($UserId, $StartingResult = 0, $NumberOfResults = 10)
55  {
56  if ($this->DebugLevel > 0) { print("REC: Recommend(${UserId}, ${StartingResult}, ${NumberOfResults})<br>\n"); }
57 
58  # load in user ratings
59  $Ratings = array();
60  $DB =& $this->DB;
61  $DB->Query("SELECT ".$this->ItemIdFieldName.", ".$this->RatingFieldName
62  ." FROM ".$this->RatingTableName
63  ." WHERE ".$this->UserIdFieldName." = ${UserId}");
64  while ($Row = $DB->FetchRow())
65  {
66  $Ratings[$Row[$this->ItemIdFieldName]] =
68  }
69  if ($this->DebugLevel > 1) { print("REC: user has rated ".count($Ratings)." items<br>\n"); }
70 
71  # for each item that user has rated
72  $RecVals = array();
73  foreach ($Ratings as $ItemId => $ItemRating)
74  {
75  # for each content correlation available for that item
76  $DB->Query("SELECT Correlation, ItemIdB "
77  ."FROM RecContentCorrelations "
78  ."WHERE ItemIdA = ${ItemId}");
79  while ($Row = $DB->FetchRow())
80  {
81  # multiply that correlation by normalized rating and add
82  # resulting value to recommendation value for that item
83  if (isset($RecVals[$Row["ItemIdB"]]))
84  {
85  $RecVals[$Row["ItemIdB"]] +=
86  $Row["Correlation"] * ($ItemRating - 50);
87  }
88  else
89  {
90  $RecVals[$Row["ItemIdB"]] =
91  $Row["Correlation"] * ($ItemRating - 50);
92  }
93  if ($this->DebugLevel > 9) { print("REC: RecVal[".$Row["ItemIdB"]."] = ".$RecVals[$Row["ItemIdB"]]."<br>\n"); }
94  }
95  }
96  if ($this->DebugLevel > 1) { print("REC: found ".count($RecVals)." total recommendations<br>\n"); }
97 
98  # calculate average correlation between items
99  $ResultThreshold = $DB->Query("SELECT AVG(Correlation) "
100  ."AS Average FROM RecContentCorrelations", "Average");
101  $ResultThreshold = round($ResultThreshold) * 2;
102 
103  # for each recommended item
104  foreach ($RecVals as $ItemId => $RecVal)
105  {
106  # remove item from list if user already rated it
107  if (isset($Ratings[$ItemId]))
108  {
109  unset($RecVals[$ItemId]);
110  }
111  else
112  {
113  # scale recommendation value back to match thresholds
114  $RecVals[$ItemId] = round($RecVal / 50);
115 
116  # remove item from recommendation list if value is below threshold
117  if ($RecVals[$ItemId] < $ResultThreshold)
118  {
119  unset($RecVals[$ItemId]);
120  }
121  }
122  }
123  if ($this->DebugLevel > 1) { print("REC: found ".count($RecVals)." positive recommendations<br>\n"); }
124 
125  # sort recommendation list by value
126  if (isset($RecVals)) { arsort($RecVals, SORT_NUMERIC); }
127 
128  # save total number of results available
129  $this->NumberOfResultsAvailable = count($RecVals);
130 
131  # trim result list to match range requested by caller
132  $RecValKeys = array_slice(
133  array_keys($RecVals), $StartingResult, $NumberOfResults);
134  $RecValSegment = array();
135  foreach ($RecValKeys as $Key)
136  {
137  $RecValSegment[$Key] = $RecVals[$Key];
138  }
139 
140  # return recommendation list to caller
141  return $RecValSegment;
142  }
143 
144  # add function to be called to filter returned recommendation list
145  function AddResultFilterFunction($FunctionName)
146  {
147  # save filter function name
148  $this->FilterFuncs[] = $FunctionName;
149  }
150 
151  # return number of recommendations generated
152  function NumberOfResults()
153  {
155  }
156 
157  # return recommendation generation time
158  function SearchTime()
159  {
160  return $this->LastSearchTime;
161  }
162 
163  # return list of items used to generate recommendation of specified item
164  function GetSourceList($UserId, $RecommendedItemId)
165  {
166  # pull list of correlations from DB
167  $this->DB->Query("SELECT * FROM RecContentCorrelations, ".$this->RatingTableName
168  ." WHERE (ItemIdA = ${RecommendedItemId}"
169  ." OR ItemIdB = ${RecommendedItemId})"
170  ." AND ".$this->UserIdFieldName." = ".$UserId
171  ." AND (RecContentCorrelations.ItemIdA = ".$this->RatingTableName.".".$this->ItemIdFieldName
172  ." OR RecContentCorrelations.ItemIdB = ".$this->RatingTableName.".".$this->ItemIdFieldName.")"
173  ." AND Rating >= 50 "
174  ." ORDER BY Correlation DESC");
175 
176  # for each correlation
177  $SourceList = array();
178  while ($Row = $this->DB->FetchRow())
179  {
180  # pick out appropriate item ID
181  if ($Row["ItemIdA"] == $RecommendedItemId)
182  {
183  $ItemId = $Row["ItemIdB"];
184  }
185  else
186  {
187  $ItemId = $Row["ItemIdA"];
188  }
189 
190  # add item to recommendation source list
191  $SourceList[$ItemId] = $Row["Correlation"];
192  }
193 
194  # return recommendation source list to caller
195  return $SourceList;
196  }
197 
198  # dynamically generate and return list of items similar to specified item
199  function FindSimilarItems($ItemId, $FieldList = NULL)
200  {
201  if ($this->DebugLevel > 1) { print("REC: searching for items similar to item \"".$ItemId."\"<br>\n"); }
202 
203  # make sure we have item IDs available
204  $this->LoadItemIds();
205 
206  # start with empty array
207  $SimilarItems = array();
208 
209  # for every item
210  foreach ($this->ItemIds as $Id)
211  {
212  # if item is not specified item
213  if ($Id != $ItemId)
214  {
215  # calculate correlation of item to specified item
216  $Correlation = $this->CalculateContentCorrelation($ItemId, $Id, $FieldList);
217 
218  # if correlation is above threshold
219  if ($Correlation > $this->ContentCorrelationThreshold)
220  {
221  # add item to list of similar items
222  $SimilarItems[$Id] = $Correlation;
223  }
224  }
225  }
226  if ($this->DebugLevel > 3) { print("REC: ".count($SimilarItems)." similar items to item \"".$ItemId."\" found<br>\n"); }
227 
228  # filter list of similar items (if any)
229  if (count($SimilarItems) > 0)
230  {
231  $SimilarItems = $this->FilterOnSuppliedFunctions($SimilarItems);
232  if ($this->DebugLevel > 4) { print("REC: ".count($SimilarItems)." similar items to item \"".$ItemId."\" left after filtering<br>\n"); }
233  }
234 
235  # if any similar items left
236  if (count($SimilarItems) > 0)
237  {
238  # sort list of similar items in order of most to least similar
239  arsort($SimilarItems, SORT_NUMERIC);
240  }
241 
242  # return list of similar items to caller
243  return $SimilarItems;
244  }
245 
246  # dynamically generate and return list of recommended field values for item
247  function RecommendFieldValues($ItemId, $FieldList = NULL)
248  {
249  if ($this->DebugLevel > 1) { print("REC: generating field value recommendations for item \"".$ItemId."\"<br>\n"); }
250 
251  # start with empty array of values
252  $RecVals = array();
253 
254  # generate list of similar items
255  $SimilarItems = $this->FindSimilarItems($ItemId, $FieldList);
256 
257  # if similar items found
258  if (count($SimilarItems) > 0)
259  {
260  # prune list of similar items to only top third of better-than-average
261  $AverageCorr = intval(array_sum($SimilarItems) / count($SimilarItems));
262  reset($SimilarItems);
263  $HighestCorr = current($SimilarItems);
264  $CorrThreshold = intval($HighestCorr - (($HighestCorr - $AverageCorr) / 3));
265  if ($this->DebugLevel > 8) { print("REC: <i>Average Correlation: $AverageCorr &nbsp;&nbsp;&nbsp;&nbsp; Highest Correlation: $HighestCorr &nbsp;&nbsp;&nbsp;&nbsp; Correlation Threshold: $CorrThreshold </i><br>\n"); }
266  foreach ($SimilarItems as $ItemId => $ItemCorr)
267  {
268  if ($ItemCorr < $CorrThreshold)
269  {
270  unset($SimilarItems[$ItemId]);
271  }
272  }
273  if ($this->DebugLevel > 6) { print("REC: ".count($SimilarItems)." similar items left after threshold pruning<br>\n"); }
274 
275  # for each item
276  foreach ($SimilarItems as $SimItemId => $SimItemCorr)
277  {
278  # for each field
279  foreach ($this->ContentFields as $FieldName => $FieldAttributes)
280  {
281  # load field data for this item
282  $FieldData = $this->GetFieldValue($SimItemId, $FieldName);
283 
284  # if field data is array
285  if (is_array($FieldData))
286  {
287  # for each field data value
288  foreach ($FieldData as $FieldDataVal)
289  {
290  # if data value is not empty
291  $FieldDataVal = trim($FieldDataVal);
292  if (strlen($FieldDataVal) > 0)
293  {
294  # increment count for data value
295  $RecVals[$FieldName][$FieldDataVal]++;
296  }
297  }
298  }
299  else
300  {
301  # if data value is not empty
302  $FieldData = trim($FieldData);
303  if (strlen($FieldData) > 0)
304  {
305  # increment count for data value
306  $RecVals[$FieldName][$FieldData]++;
307  }
308  }
309  }
310  }
311 
312  # for each field
313  $MatchingCountThreshold = 3;
314  foreach ($RecVals as $FieldName => $FieldVals)
315  {
316  # determine cutoff threshold
317  arsort($FieldVals, SORT_NUMERIC);
318  reset($FieldVals);
319  $HighestCount = current($FieldVals);
320  $AverageCount = intval(array_sum($FieldVals) / count($FieldVals));
321  $CountThreshold = intval($AverageCount + (($HighestCount - $AverageCount) / 2));
322  if ($CountThreshold < $MatchingCountThreshold) { $CountThreshold = $MatchingCountThreshold; }
323  if ($this->DebugLevel > 8) { print("REC: <i>Field: $FieldName &nbsp;&nbsp;&nbsp;&nbsp; Average Count: $AverageCount &nbsp;&nbsp;&nbsp;&nbsp; Highest Count: $HighestCount &nbsp;&nbsp;&nbsp;&nbsp; Count Threshold: $CountThreshold </i><br>\n"); }
324 
325  # for each field data value
326  foreach ($FieldVals as $FieldVal => $FieldValCount)
327  {
328  # if value count is below threshold
329  if ($FieldValCount < $CountThreshold)
330  {
331  # unset value
332  unset($RecVals[$FieldName][$FieldVal]);
333  }
334  }
335 
336  if ($this->DebugLevel > 3) { print("REC: found ".count($RecVals[$FieldName])." recommended values for field \"".$FieldName."\" after threshold pruning<br>\n"); }
337  }
338  }
339 
340  # return recommended values to caller
341  return $RecVals;
342  }
343 
344 
345  # ---- database update methods
346 
347  function UpdateForItems($StartingItemId, $NumberOfItems)
348  {
349  if ($this->DebugLevel > 0) { print("REC: UpdateForItems(${StartingItemId}, ${NumberOfItems})<br>\n"); }
350  # make sure we have item IDs available
351  $this->LoadItemIds();
352 
353  # for every item
354  $ItemsUpdated = 0;
355  $ItemId = NULL;
356  foreach ($this->ItemIds as $ItemId)
357  {
358  # if item ID is within requested range
359  if ($ItemId >= $StartingItemId)
360  {
361  # update recommender info for item
362  if ($this->DebugLevel > 1) { print("REC: doing item ${ItemId}<br>\n"); }
363  $this->UpdateForItem($ItemId, TRUE);
364  $ItemsUpdated++;
365 
366  # if we have done requested number of items
367  if ($ItemsUpdated >= $NumberOfItems)
368  {
369  # bail out
370  if ($this->DebugLevel > 1) { print("REC: bailing out with item ${ItemId}<br>\n"); }
371  return $ItemId;
372  }
373  }
374  }
375 
376  # return ID of last resource updated to caller
377  return $ItemId;
378  }
379 
380  function UpdateForItem($ItemId, $FullPass = FALSE)
381  {
382  if ($this->DebugLevel > 1) { print("REC: updating for item \"".$ItemId."\"<br>\n"); }
383 
384  # make sure we have item IDs available
385  $this->LoadItemIds();
386 
387  # clear existing correlations for this item
388  $this->DB->Query("DELETE FROM RecContentCorrelations "
389  ."WHERE ItemIdA = ${ItemId}");
390 
391  # for every item
392  foreach ($this->ItemIds as $Id)
393  {
394  # if full pass and item is later in list than current item
395  if (($FullPass == FALSE) || ($Id > $ItemId))
396  {
397  # update correlation value for item and target item
398  $this->UpdateContentCorrelation($ItemId, $Id);
399  }
400  }
401  }
402 
403  function DropItem($ItemId)
404  {
405  # drop all correlation entries referring to item
406  $this->DB->Query("DELETE FROM RecContentCorrelations "
407  ."WHERE ItemIdA = ".$ItemId." "
408  ."OR ItemIdB = ".$ItemId);
409  }
410 
411  function PruneCorrelations()
412  {
413  # get average correlation
414  $AverageCorrelation = $this->DB->Query("SELECT AVG(Correlation) "
415  ."AS Average FROM RecContentCorrelations", "Average");
416 
417  # dump all below-average correlations
418  if ($AverageCorrelation > 0)
419  {
420  $this->DB->Query("DELETE FROM RecContentCorrelations "
421  ."WHERE Correlation <= ${AverageCorrelation}");
422  }
423  }
424 
429  function GetItemIds()
430  {
431  static $ItemIds;
432  if (!isset($ItemIds))
433  {
434  $this->DB->Query("SELECT ".$this->ItemIdFieldName." AS Id FROM "
435  .$this->ItemTableName." ORDER BY ".$this->ItemIdFieldName);
436  $ItemIds = $this->DB->FetchColumn("Id");
437  }
438  return $ItemIds;
439  }
440 
441 
442  # ---- PRIVATE INTERFACE -------------------------------------------------
443 
451  var $ItemIds;
452  var $DB;
457 
458 
459  function LoadItemIds()
460  {
461  # if item IDs not already loaded
462  if (!isset($this->ItemIds))
463  {
464  # load item IDs from DB
465  $this->DB->Query("SELECT ".$this->ItemIdFieldName." AS Id FROM "
466  .$this->ItemTableName." ORDER BY ".$this->ItemIdFieldName);
467  $this->ItemIds = array();
468  while ($Item = $this->DB->FetchRow())
469  {
470  $this->ItemIds[] = $Item["Id"];
471  }
472  }
473  }
474 
475  function GetFieldData($ItemId, $FieldName)
476  {
477  static $ItemData;
478 
479  # if data not already loaded
480  if (!isset($ItemData[$ItemId][$FieldName]))
481  {
482  # load field value from DB
483  $FieldValue = $this->GetFieldValue($ItemId, $FieldName);
484 
485  # if field value is array
486  if (is_array($FieldValue))
487  {
488  # concatenate together text from array elements
489  $FieldValue = implode(" ", $FieldValue);
490  }
491 
492  # normalize text and break into word array
493  $ItemData[$ItemId][$FieldName] = $this->NormalizeAndParseText($FieldValue);
494  }
495 
496  # return cached data to caller
497  return $ItemData[$ItemId][$FieldName];
498  }
499 
500  # calculate content correlation between two items and return value to caller
501  function CalculateContentCorrelation($ItemIdA, $ItemIdB, $FieldList = NULL)
502  {
503  static $CorrelationCache;
504 
505  if ($this->DebugLevel > 10) { print("REC: calculating correlation"
506  ." between items $ItemIdA and $ItemIdB<br>\n"); }
507 
508  # order item ID numbers
509  if ($ItemIdA > $ItemIdB)
510  {
511  $Temp = $ItemIdA;
512  $ItemIdA = $ItemIdB;
513  $ItemIdB = $Temp;
514  }
515 
516  # if we already have the correlation
517  if (isset($CorrelationCache[$ItemIdA][$ItemIdB]))
518  {
519  # retrieve correlation from cache
520  $TotalCorrelation = $CorrelationCache[$ItemIdA][$ItemIdB];
521  }
522  else
523  {
524  # if list of fields to correlate specified
525  if ($FieldList != NULL)
526  {
527  # create list with only specified fields
528  foreach ($FieldList as $FieldName)
529  {
530  $ContentFields[$FieldName] = $this->ContentFields[$FieldName];
531  }
532  }
533  else
534  {
535  # use all fields
537  }
538 
539  # for each content field
540  $TotalCorrelation = 0;
541  foreach ($ContentFields as $FieldName => $FieldAttributes)
542  {
543  # if field is of a type that we use for correlation
544  $FieldType = intval($FieldAttributes["FieldType"]);
545  if (($FieldType == Recommender::CONTENTFIELDTYPE_TEXT)
547  {
548  # load data
549  $ItemAData = $this->GetFieldData($ItemIdA, $FieldName);
550  $ItemBData = $this->GetFieldData($ItemIdB, $FieldName);
551  if ($this->DebugLevel > 15) { print("REC: loaded ".count($ItemAData)." terms for item #".$ItemIdA." and ".count($ItemBData)." terms for item #".$ItemIdB." for field \"".$FieldName."\"<br>\n"); }
552 
553  # call appropriate routine to get correlation
554  switch ($FieldType)
555  {
558  $Correlation = $this->CalcTextCorrelation(
559  $ItemAData, $ItemBData);
560  break;
561  }
562 
563  # add correlation multiplied by weight to total
564  $TotalCorrelation += $Correlation * $FieldAttributes["Weight"];
565  }
566  }
567 
568  # store correlation to cache
569  $CorrelationCache[$ItemIdA][$ItemIdB] = $TotalCorrelation;
570  }
571 
572  # return correlation value to caller
573  if ($this->DebugLevel > 9) { print("REC: correlation between items $ItemIdA and $ItemIdB found to be $TotalCorrelation<br>\n"); }
574  return $TotalCorrelation;
575  }
576 
577  # calculate content correlation between two items and update in DB
578  function UpdateContentCorrelation($ItemIdA, $ItemIdB)
579  {
580  if ($this->DebugLevel > 6) { print("REC: updating correlation between items $ItemIdA and $ItemIdB<br>\n"); }
581 
582  # bail out if two items are the same
583  if ($ItemIdA == $ItemIdB) { return; }
584 
585  # calculate correlation
586  $Correlation = $this->CalculateContentCorrelation($ItemIdA, $ItemIdB);
587 
588  # save new correlation
589  $this->ContentCorrelation($ItemIdA, $ItemIdB, $Correlation);
590  }
591 
592  function NormalizeAndParseText($Text)
593  {
594  $StopWords = array(
595  "a",
596  "about",
597  "also",
598  "an",
599  "and",
600  "are",
601  "as",
602  "at",
603  "be",
604  "but",
605  "by",
606  "can",
607  "each",
608  "either",
609  "for",
610  "from",
611  "has",
612  "he",
613  "her",
614  "here",
615  "hers",
616  "him",
617  "his",
618  "how",
619  "i",
620  "if",
621  "in",
622  "include",
623  "into",
624  "is",
625  "it",
626  "its",
627  "me",
628  "neither",
629  "no",
630  "nor",
631  "not",
632  "of",
633  "on",
634  "or",
635  "so",
636  "she",
637  "than",
638  "that",
639  "the",
640  "their",
641  "them",
642  "then",
643  "there",
644  "these",
645  "they",
646  "this",
647  "those",
648  "through",
649  "to",
650  "too",
651  "very",
652  "what",
653  "when",
654  "where",
655  "while",
656  "who",
657  "why",
658  "will",
659  "you",
660  "");
661 
662  # strip any HTML tags
663  $Text = strip_tags($Text);
664 
665  # strip any punctuation
666  $Text = preg_replace("/,\\.\\?-\\(\\)\\[\\]\"/", " ", $Text); # "
667 
668  # normalize whitespace
669  $Text = trim(preg_replace("/[\\s]+/", " ", $Text));
670 
671  # convert to all lower case
672  $Text = strtolower($Text);
673 
674  # split text into arrays of words
675  $Words = explode(" ", $Text);
676 
677  # filter out all stop words
678  $Words = array_diff($Words, $StopWords);
679 
680  # return word array to caller
681  return $Words;
682  }
683 
684  function CalcTextCorrelation($WordsA, $WordsB)
685  {
686  # get array containing intersection of two word arrays
687  $IntersectWords = array_intersect($WordsA, $WordsB);
688 
689  # return number of words remaining as score
690  return count($IntersectWords);
691  }
692 
693  function ContentCorrelation($ItemIdA, $ItemIdB, $NewCorrelation = -1)
694  {
695  # if item ID A is greater than item ID B
696  if ($ItemIdA > $ItemIdB)
697  {
698  # swap item IDs
699  $Temp = $ItemIdA;
700  $ItemIdA = $ItemIdB;
701  $ItemIdB = $Temp;
702  }
703 
704  # if new correlation value provided
705  if ($NewCorrelation != -1)
706  {
707  # if new value is above threshold
708  if ($NewCorrelation >= $this->ContentCorrelationThreshold)
709  {
710  # insert new correlation value in DB
711  $this->DB->Query("INSERT INTO RecContentCorrelations "
712  ."(ItemIdA, ItemIdB, Correlation) "
713  ."VALUES (${ItemIdA}, ${ItemIdB}, ${NewCorrelation})");
714 
715  # return correlation value is new value
716  $Correlation = $NewCorrelation;
717  }
718  # else
719  else
720  {
721  # return value is zero
722  $Correlation = 0;
723  }
724  }
725  else
726  {
727  # retrieve correlation value from DB
728  $Correlation = $this->DB->Query(
729  "SELECT Correlation FROM RecContentCorrelations "
730  ."WHERE ItemIdA = ${ItemIdA} AND ItemIdB = ${ItemIdB}",
731  "Correlation");
732 
733  # if no value found in DB
734  if ($Correlation == FALSE)
735  {
736  # return value is zero
737  $Correlation = 0;
738  }
739  }
740 
741  # return correlation value to caller
742  return $Correlation;
743  }
744 
745  function FilterOnSuppliedFunctions($Results)
746  {
747  # if filter functions have been set
748  if (count($this->FilterFuncs) > 0)
749  {
750  # for each result
751  foreach ($Results as $ResourceId => $Result)
752  {
753  # for each filter function
754  foreach ($this->FilterFuncs as $FuncName)
755  {
756  # if filter function return TRUE for result resource
757  if ($FuncName($ResourceId))
758  {
759  # discard result
760  if ($this->DebugLevel > 2) { print("REC: filter callback rejected resource ${ResourceId}<br>\n"); }
761  unset($Results[$ResourceId]);
762 
763  # bail out of filter func loop
764  continue 2;
765  }
766  }
767  }
768  }
769 
770  # return filtered list to caller
771  return $Results;
772  }
773 }
774 
775 ?>
DebugLevel($Setting)
Definition: Recommender.php:45
RecommendFieldValues($ItemId, $FieldList=NULL)
UpdateForItems($StartingItemId, $NumberOfItems)
GetSourceList($UserId, $RecommendedItemId)
ContentCorrelation($ItemIdA, $ItemIdB, $NewCorrelation=-1)
const CONTENTFIELDTYPE_CONTROLLEDNAME
Definition: Recommender.php:17
AddResultFilterFunction($FunctionName)
const CONTENTFIELDTYPE_DATE
Definition: Recommender.php:18
FilterOnSuppliedFunctions($Results)
GetItemIds()
Retrieve all item IDs.
UpdateForItem($ItemId, $FullPass=FALSE)
const CONTENTFIELDTYPE_NUMERIC
Definition: Recommender.php:16
GetFieldData($ItemId, $FieldName)
UpdateContentCorrelation($ItemIdA, $ItemIdB)
PHP
Definition: OAIClient.php:39
Recommend($UserId, $StartingResult=0, $NumberOfResults=10)
Definition: Recommender.php:54
CalcTextCorrelation($WordsA, $WordsB)
const CONTENTFIELDTYPE_TEXT
Definition: Recommender.php:15
Recommender(&$DB, $ItemTableName, $RatingTableName, $ItemIdFieldName, $UserIdFieldName, $RatingFieldName, $ContentFields)
Definition: Recommender.php:22
FindSimilarItems($ItemId, $FieldList=NULL)
const CONTENTFIELDTYPE_DATERAMGE
Definition: Recommender.php:19
NormalizeAndParseText($Text)
CalculateContentCorrelation($ItemIdA, $ItemIdB, $FieldList=NULL)
$ContentCorrelationThreshold
DropItem($ItemId)