CWIS Developer Documentation

- Home
- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

Recommender.php
Go to the documentation of this file.
1 <?PHP
2 #
3 # FILE: Recommender.php
4 #
5 # Part of the Collection Workflow Integration System (CWIS)
6 # Copyright 2004-2017 Edward Almasy and Internet Scout Research Group
7 # http://scout.wisc.edu/cwis/
8 #
9
13 class Recommender
14 {
15
16 # ---- PUBLIC INTERFACE --------------------------------------------------
17 # define content field types
18 const CONTENTFIELDTYPE_TEXT = 1;
19 const CONTENTFIELDTYPE_NUMERIC = 2;
20 const CONTENTFIELDTYPE_CONTROLLEDNAME = 3;
21 const CONTENTFIELDTYPE_DATE = 4;
22 const CONTENTFIELDTYPE_DATERAMGE = 5;
23
41 public function __construct(&$DB, $ItemTableName, $RatingTableName,
42 $ItemIdFieldName, $UserIdFieldName, $RatingFieldName,
43 $ContentFields)
44 {
45 # set default parameters
46 $this->ContentCorrelationThreshold = 1;
47
48 # save database object
49 $this->DB =& $DB;
50
51 # save new configuration values
52 $this->ItemTableName = $ItemTableName;
53 $this->RatingTableName = $RatingTableName;
54 $this->ItemIdFieldName = $ItemIdFieldName;
55 $this->UserIdFieldName = $UserIdFieldName;
56 $this->RatingFieldName = $RatingFieldName;
57 $this->ContentFields = $ContentFields;
58
59 # set default debug state
60 $this->DebugLevel = 0;
61 }
62
67 public function DebugLevel($Setting)
68 {
69 $this->DebugLevel = $Setting;
70 }
71
72
73 # ---- recommendation methods
74
83 public function Recommend($UserId, $StartingResult = 0, $NumberOfResults = 10)
84 {
85 if ($this->DebugLevel > 0)
86 {
87 print "REC: Recommend(${UserId}, ${StartingResult},"
88 ." ${NumberOfResults})<br>\n";
89 }
90
91 # load in user ratings
92 $Ratings = array();
93 $DB =& $this->DB;
94 $DB->Query("SELECT ".$this->ItemIdFieldName.", ".$this->RatingFieldName
95 ." FROM ".$this->RatingTableName
96 ." WHERE ".$this->UserIdFieldName." = ${UserId}");
97 while ($Row = $DB->FetchRow())
98 {
99 $Ratings[$Row[$this->ItemIdFieldName]] =
100 $Row[$this->RatingFieldName];
101 }
102 if ($this->DebugLevel > 1)
103 {
104 print "REC: user has rated ".count($Ratings)." items<br>\n";
105 }
106
107 # for each item that user has rated
108 $RecVals = array();
109 foreach ($Ratings as $ItemId => $ItemRating)
110 {
111 # for each content correlation available for that item
112 $DB->Query("SELECT Correlation, ItemIdB "
113 ."FROM RecContentCorrelations "
114 ."WHERE ItemIdA = ${ItemId}");
115 while ($Row = $DB->FetchRow())
116 {
117 # multiply that correlation by normalized rating and add
118 # resulting value to recommendation value for that item
119 if (isset($RecVals[$Row["ItemIdB"]]))
120 {
121 $RecVals[$Row["ItemIdB"]] +=
122 $Row["Correlation"] * ($ItemRating - 50);
123 }
124 else
125 {
126 $RecVals[$Row["ItemIdB"]] =
127 $Row["Correlation"] * ($ItemRating - 50);
128 }
129 if ($this->DebugLevel > 9)
130 {
131 print "REC: RecVal[".$Row["ItemIdB"]."] = "
132 .$RecVals[$Row["ItemIdB"]]."<br>\n";
133 }
134 }
135 }
136 if ($this->DebugLevel > 1)
137 {
138 print "REC: found ".count($RecVals)." total recommendations<br>\n";
139 }
140
141 # calculate average correlation between items
142 $ResultThreshold = $DB->Query("SELECT AVG(Correlation) "
143 ."AS Average FROM RecContentCorrelations", "Average");
144 $ResultThreshold = round($ResultThreshold) * 2;
145
146 # for each recommended item
147 foreach ($RecVals as $ItemId => $RecVal)
148 {
149 # remove item from list if user already rated it
150 if (isset($Ratings[$ItemId]))
151 {
152 unset($RecVals[$ItemId]);
153 }
154 else
155 {
156 # scale recommendation value back to match thresholds
157 $RecVals[$ItemId] = round($RecVal / 50);
158
159 # remove item from recommendation list if value is below threshold
160 if ($RecVals[$ItemId] < $ResultThreshold)
161 {
162 unset($RecVals[$ItemId]);
163 }
164 }
165 }
166 if ($this->DebugLevel > 1)
167 {
168 print "REC: found ".count($RecVals)." positive recommendations<br>\n";
169 }
170
171 # sort recommendation list by value
172 if (isset($RecVals)) { arsort($RecVals, SORT_NUMERIC); }
173
174 # save total number of results available
175 $this->NumberOfResultsAvailable = count($RecVals);
176
177 # trim result list to match range requested by caller
178 $RecValKeys = array_slice(
179 array_keys($RecVals), $StartingResult, $NumberOfResults);
180 $RecValSegment = array();
181 foreach ($RecValKeys as $Key)
182 {
183 $RecValSegment[$Key] = $RecVals[$Key];
184 }
185
186 # return recommendation list to caller
187 return $RecValSegment;
188 }
189
195 public function AddResultFilterFunction($FunctionName)
196 {
197 # save filter function name
198 $this->FilterFuncs[] = $FunctionName;
199 }
200
205 public function NumberOfResults()
206 {
207 return $this->NumberOfResultsAvailable;
208 }
209
214 public function SearchTime()
215 {
216 return $this->LastSearchTime;
217 }
218
228 public function GetSourceList($UserId, $RecommendedItemId)
229 {
230 # pull list of correlations from DB
231 $this->DB->Query("SELECT * FROM RecContentCorrelations, ".$this->RatingTableName
232 ." WHERE (ItemIdA = ${RecommendedItemId}"
233 ." OR ItemIdB = ${RecommendedItemId})"
234 ." AND ".$this->UserIdFieldName." = ".$UserId
235 ." AND (RecContentCorrelations.ItemIdA = "
236 .$this->RatingTableName.".".$this->ItemIdFieldName
237 ." OR RecContentCorrelations.ItemIdB = "
238 .$this->RatingTableName.".".$this->ItemIdFieldName.")"
239 ." AND Rating >= 50 "
240 ." ORDER BY Correlation DESC");
241
242 # for each correlation
243 $SourceList = array();
244 while ($Row = $this->DB->FetchRow())
245 {
246 # pick out appropriate item ID
247 if ($Row["ItemIdA"] == $RecommendedItemId)
248 {
249 $ItemId = $Row["ItemIdB"];
250 }
251 else
252 {
253 $ItemId = $Row["ItemIdA"];
254 }
255
256 # add item to recommendation source list
257 $SourceList[$ItemId] = $Row["Correlation"];
258 }
259
260 # return recommendation source list to caller
261 return $SourceList;
262 }
263
271 public function FindSimilarItems($ItemId, $FieldList = NULL)
272 {
273 if ($this->DebugLevel > 1)
274 {
275 print "REC: searching for items similar to item \""
276 .$ItemId."\"<br>\n";
277 }
278
279 # make sure we have item IDs available
280 $this->LoadItemIds();
281
282 # start with empty array
283 $SimilarItems = array();
284
285 # for every item
286 foreach ($this->ItemIds as $Id)
287 {
288 # if item is not specified item
289 if ($Id != $ItemId)
290 {
291 # calculate correlation of item to specified item
292 $Correlation = $this->CalculateContentCorrelation(
293 $ItemId, $Id, $FieldList);
294
295 # if correlation is above threshold
296 if ($Correlation > $this->ContentCorrelationThreshold)
297 {
298 # add item to list of similar items
299 $SimilarItems[$Id] = $Correlation;
300 }
301 }
302 }
303 if ($this->DebugLevel > 3)
304 {
305 print "REC: ".count($SimilarItems)." similar items to item \""
306 .$ItemId."\" found<br>\n";
307 }
308
309 # filter list of similar items (if any)
310 if (count($SimilarItems) > 0)
311 {
312 $SimilarItems = $this->FilterOnSuppliedFunctions($SimilarItems);
313 if ($this->DebugLevel > 4)
314 {
315 print "REC: ".count($SimilarItems)." similar items to item \""
316 .$ItemId."\" left after filtering<br>\n";
317 }
318 }
319
320 # if any similar items left
321 if (count($SimilarItems) > 0)
322 {
323 # sort list of similar items in order of most to least similar
324 arsort($SimilarItems, SORT_NUMERIC);
325 }
326
327 # return list of similar items to caller
328 return $SimilarItems;
329 }
330
339 public function RecommendFieldValues($ItemId, $FieldList = NULL)
340 {
341 if ($this->DebugLevel > 1)
342 {
343 print "REC: generating field value recommendations for item \""
344 .$ItemId."\"<br>\n";
345 }
346
347 # start with empty array of values
348 $RecVals = array();
349
350 # generate list of similar items
351 $SimilarItems = $this->FindSimilarItems($ItemId, $FieldList);
352
353 # if similar items found
354 if (count($SimilarItems) > 0)
355 {
356 # prune list of similar items to only top third of better-than-average
357 $AverageCorr = intval(array_sum($SimilarItems) / count($SimilarItems));
358 reset($SimilarItems);
359 $HighestCorr = current($SimilarItems);
360 $CorrThreshold = intval($HighestCorr - (($HighestCorr - $AverageCorr) / 3));
361 if ($this->DebugLevel > 8)
362 {
363 print "REC: <i>Average Correlation: $AverageCorr"
364 ." &nbsp;&nbsp;&nbsp;&nbsp; Highest Correlation:"
365 ." $HighestCorr &nbsp;&nbsp;&nbsp;&nbsp; Correlation"
366 ." Threshold: $CorrThreshold </i><br>\n";
367 }
368 foreach ($SimilarItems as $ItemId => $ItemCorr)
369 {
370 if ($ItemCorr < $CorrThreshold)
371 {
372 unset($SimilarItems[$ItemId]);
373 }
374 }
375 if ($this->DebugLevel > 6)
376 {
377 print "REC: ".count($SimilarItems)
378 ." similar items left after threshold pruning<br>\n";
379 }
380
381 # for each item
382 foreach ($SimilarItems as $SimItemId => $SimItemCorr)
383 {
384 # for each field
385 foreach ($this->ContentFields as $FieldName => $FieldAttributes)
386 {
387 # load field data for this item
388 $FieldData = $this->GetFieldValue($SimItemId, $FieldName);
389
390 # if field data is array
391 if (is_array($FieldData))
392 {
393 # for each field data value
394 foreach ($FieldData as $FieldDataVal)
395 {
396 # if data value is not empty
397 $FieldDataVal = trim($FieldDataVal);
398 if (strlen($FieldDataVal) > 0)
399 {
400 # increment count for data value
401 $RecVals[$FieldName][$FieldDataVal]++;
402 }
403 }
404 }
405 else
406 {
407 # if data value is not empty
408 $FieldData = trim($FieldData);
409 if (strlen($FieldData) > 0)
410 {
411 # increment count for data value
412 $RecVals[$FieldName][$FieldData]++;
413 }
414 }
415 }
416 }
417
418 # for each field
419 $MatchingCountThreshold = 3;
420 foreach ($RecVals as $FieldName => $FieldVals)
421 {
422 # determine cutoff threshold
423 arsort($FieldVals, SORT_NUMERIC);
424 reset($FieldVals);
425 $HighestCount = current($FieldVals);
426 $AverageCount = intval(array_sum($FieldVals) / count($FieldVals));
427 $CountThreshold = intval($AverageCount
428 + (($HighestCount - $AverageCount) / 2));
429 if ($CountThreshold < $MatchingCountThreshold)
430 {
431 $CountThreshold = $MatchingCountThreshold;
432 }
433 if ($this->DebugLevel > 8)
434 {
435 print "REC: <i>Field: $FieldName &nbsp;&nbsp;&nbsp;&nbsp;"
436 ." Average Count: $AverageCount &nbsp;&nbsp;&nbsp;&nbsp;"
437 ." Highest Count: $HighestCount &nbsp;&nbsp;&nbsp;&nbsp;"
438 ." Count Threshold: $CountThreshold </i><br>\n";
439 }
440
441 # for each field data value
442 foreach ($FieldVals as $FieldVal => $FieldValCount)
443 {
444 # if value count is below threshold
445 if ($FieldValCount < $CountThreshold)
446 {
447 # unset value
448 unset($RecVals[$FieldName][$FieldVal]);
449 }
450 }
451
452 if ($this->DebugLevel > 3)
453 {
454 print "REC: found ".count($RecVals[$FieldName])
455 ." recommended values for field \""
456 .$FieldName."\" after threshold pruning<br>\n";
457 }
458 }
459 }
460
461 # return recommended values to caller
462 return $RecVals;
463 }
464
465
466 # ---- database update methods
467
474 public function UpdateForItems($StartingItemId, $NumberOfItems)
475 {
476 if ($this->DebugLevel > 0)
477 {
478 print "REC: UpdateForItems(${StartingItemId},"
479 ." ${NumberOfItems})<br>\n";
480 }
481 # make sure we have item IDs available
482 $this->LoadItemIds();
483
484 # for every item
485 $ItemsUpdated = 0;
486 $ItemId = NULL;
487 foreach ($this->ItemIds as $ItemId)
488 {
489 # if item ID is within requested range
490 if ($ItemId >= $StartingItemId)
491 {
492 # update recommender info for item
493 if ($this->DebugLevel > 1)
494 { print("REC: doing item ${ItemId}<br>\n"); }
495 $this->UpdateForItem($ItemId, TRUE);
496 $ItemsUpdated++;
497
498 # if we have done requested number of items
499 if ($ItemsUpdated >= $NumberOfItems)
500 {
501 # bail out
502 if ($this->DebugLevel > 1)
503 {
504 print "REC: bailing out with item ${ItemId}<br>\n";
505 }
506 return $ItemId;
507 }
508 }
509 }
510
511 # return ID of last item updated to caller
512 return $ItemId;
513 }
514
521 public function UpdateForItem($ItemId, $FullPass = FALSE)
522 {
523 if ($this->DebugLevel > 1)
524 {
525 print "REC: updating for item \"".$ItemId."\"<br>\n";
526 }
527
528 # make sure we have item IDs available
529 $this->LoadItemIds();
530
531 # clear existing correlations for this item
532 $this->DB->Query("DELETE FROM RecContentCorrelations "
533 ."WHERE ItemIdA = ${ItemId}");
534
535 # for every item
536 foreach ($this->ItemIds as $Id)
537 {
538 # if full pass and item is later in list than current item
539 if (($FullPass == FALSE) || ($Id > $ItemId))
540 {
541 # update correlation value for item and target item
542 $this->UpdateContentCorrelation($ItemId, $Id);
543 }
544 }
545 }
546
551 public function DropItem($ItemId)
552 {
553 # drop all correlation entries referring to item
554 $this->DB->Query("DELETE FROM RecContentCorrelations "
555 ."WHERE ItemIdA = ".$ItemId." "
556 ."OR ItemIdB = ".$ItemId);
557 }
558
562 public function PruneCorrelations()
563 {
564 # get average correlation
565 $AverageCorrelation = $this->DB->Query("SELECT AVG(Correlation) "
566 ."AS Average FROM RecContentCorrelations", "Average");
567
568 # dump all below-average correlations
569 if ($AverageCorrelation > 0)
570 {
571 $this->DB->Query("DELETE FROM RecContentCorrelations "
572 ."WHERE Correlation <= ${AverageCorrelation}");
573 }
574 }
575
580 public function GetItemIds()
581 {
582 if (self::$ItemIdCache === NULL)
583 {
584 $this->DB->Query("SELECT ".$this->ItemIdFieldName." AS Id FROM "
585 .$this->ItemTableName." ORDER BY ".$this->ItemIdFieldName);
586 self::$ItemIdCache = $this->DB->FetchColumn("Id");
587 }
588 return self::$ItemIdCache;
589 }
590
595 static public function ClearCaches()
596 {
597 self::$CorrelationCache = NULL;
598 self::$ItemIdCache = NULL;
599 self::$ItemDataCache = NULL;
600 }
601
602
603 # ---- PRIVATE INTERFACE -------------------------------------------------
604
605 private $ContentCorrelationThreshold;
606 private $ContentFields;
607 private $ItemTableName;
608 private $RatingTableName;
609 private $ItemIdFieldName;
610 private $UserIdFieldName;
611 private $RatingFieldName;
612 private $ItemIds;
613 private $DB;
614 private $FilterFuncs;
615 private $LastSearchTime;
616 private $NumberOfResultsAvailable;
617 private $DebugLevel;
618
619 static private $ItemIdCache = NULL;
620 static private $ItemDataCache = NULL;
621 static private $CorrelationCache = NULL;
622
626 protected function LoadItemIds()
627 {
628 # if item IDs not already loaded
629 if (!isset($this->ItemIds))
630 {
631 # load item IDs from DB
632 $this->DB->Query("SELECT ".$this->ItemIdFieldName." AS Id FROM "
633 .$this->ItemTableName." ORDER BY ".$this->ItemIdFieldName);
634 $this->ItemIds[] = $this->DB->FetchColumn("Id");
635 }
636 }
637
644 protected function GetFieldData($ItemId, $FieldName)
645 {
646 # if data not already loaded
647 if (!isset(self::$ItemDataCache[$ItemId][$FieldName]))
648 {
649 # load field value from DB
650 $FieldValue = $this->GetFieldValue($ItemId, $FieldName);
651
652 # if field value is array
653 if (is_array($FieldValue))
654 {
655 # concatenate together text from array elements
656 $FieldValue = implode(" ", $FieldValue);
657 }
658
659 # normalize text and break into word array
660 self::$ItemDataCache[$ItemId][$FieldName] =
661 $this->NormalizeAndParseText($FieldValue);
662 }
663
664 # return cached data to caller
665 return self::$ItemDataCache[$ItemId][$FieldName];
666 }
667
676 protected function CalculateContentCorrelation($ItemIdA, $ItemIdB, $FieldList = NULL)
677 {
678 if ($this->DebugLevel > 10) { print("REC: calculating correlation"
679 ." between items $ItemIdA and $ItemIdB<br>\n"); }
680
681 # order item ID numbers
682 if ($ItemIdA > $ItemIdB)
683 {
684 $Temp = $ItemIdA;
685 $ItemIdA = $ItemIdB;
686 $ItemIdB = $Temp;
687 }
688
689 # if we already have the correlation
690 if (isset(self::$CorrelationCache[$ItemIdA][$ItemIdB]))
691 {
692 # retrieve correlation from cache
693 $TotalCorrelation = self::$CorrelationCache[$ItemIdA][$ItemIdB];
694 }
695 else
696 {
697 # if list of fields to correlate specified
698 if ($FieldList != NULL)
699 {
700 # create list with only specified fields
701 foreach ($FieldList as $FieldName)
702 {
703 $ContentFields[$FieldName] = $this->ContentFields[$FieldName];
704 }
705 }
706 else
707 {
708 # use all fields
709 $ContentFields = $this->ContentFields;
710 }
711
712 # for each content field
713 $TotalCorrelation = 0;
714 foreach ($ContentFields as $FieldName => $FieldAttributes)
715 {
716 # if field is of a type that we use for correlation
717 $FieldType = intval($FieldAttributes["FieldType"]);
718 if (($FieldType == self::CONTENTFIELDTYPE_TEXT)
719 || ($FieldType == self::CONTENTFIELDTYPE_CONTROLLEDNAME))
720 {
721 # load data
722 $ItemAData = $this->GetFieldData($ItemIdA, $FieldName);
723 $ItemBData = $this->GetFieldData($ItemIdB, $FieldName);
724 if ($this->DebugLevel > 15)
725 {
726 print "REC: loaded ".count($ItemAData)
727 ." terms for item #".$ItemIdA." and "
728 .count($ItemBData)." terms for item #"
729 .$ItemIdB." for field \"".$FieldName."\"<br>\n";
730 }
731
732 # call appropriate routine to get correlation
733 switch ($FieldType)
734 {
735 case self::CONTENTFIELDTYPE_TEXT:
736 case self::CONTENTFIELDTYPE_CONTROLLEDNAME:
737 $Correlation = $this->CalcTextCorrelation(
738 $ItemAData, $ItemBData);
739 break;
740 }
741
742 # add correlation multiplied by weight to total
743 $TotalCorrelation += $Correlation * $FieldAttributes["Weight"];
744 }
745 }
746
747 # store correlation to cache
748 self::$CorrelationCache[$ItemIdA][$ItemIdB] = $TotalCorrelation;
749 }
750
751 # return correlation value to caller
752 if ($this->DebugLevel > 9)
753 {
754 print("REC: correlation between items $ItemIdA and $ItemIdB"
755 ." found to be $TotalCorrelation<br>\n");
756 }
757 return $TotalCorrelation;
758 }
759
765 protected function UpdateContentCorrelation($ItemIdA, $ItemIdB)
766 {
767 if ($this->DebugLevel > 6) { print("REC: updating correlation between"
768 ." items $ItemIdA and $ItemIdB<br>\n"); }
769
770 # bail out if two items are the same
771 if ($ItemIdA == $ItemIdB) { return; }
772
773 # calculate correlation
774 $Correlation = $this->CalculateContentCorrelation($ItemIdA, $ItemIdB);
775
776 # save new correlation
777 $this->ContentCorrelation($ItemIdA, $ItemIdB, $Correlation);
778 }
779
785 protected function NormalizeAndParseText($Text)
786 {
787 $StopWords = array(
788 "a",
789 "about",
790 "also",
791 "an",
792 "and",
793 "are",
794 "as",
795 "at",
796 "be",
797 "but",
798 "by",
799 "can",
800 "each",
801 "either",
802 "for",
803 "from",
804 "has",
805 "he",
806 "her",
807 "here",
808 "hers",
809 "him",
810 "his",
811 "how",
812 "i",
813 "if",
814 "in",
815 "include",
816 "into",
817 "is",
818 "it",
819 "its",
820 "me",
821 "neither",
822 "no",
823 "nor",
824 "not",
825 "of",
826 "on",
827 "or",
828 "so",
829 "she",
830 "than",
831 "that",
832 "the",
833 "their",
834 "them",
835 "then",
836 "there",
837 "these",
838 "they",
839 "this",
840 "those",
841 "through",
842 "to",
843 "too",
844 "very",
845 "what",
846 "when",
847 "where",
848 "while",
849 "who",
850 "why",
851 "will",
852 "you",
853 "");
854
855 # strip any HTML tags
856 $Text = strip_tags($Text);
857
858 # strip any punctuation
859 $Text = preg_replace("/,\\.\\?-\\(\\)\\[\\]\"/", " ", $Text); # "
860
861 # normalize whitespace
862 $Text = trim(preg_replace("/[\\s]+/", " ", $Text));
863
864 # convert to all lower case
865 $Text = strtolower($Text);
866
867 # split text into arrays of words
868 $Words = explode(" ", $Text);
869
870 # filter out all stop words
871 $Words = array_diff($Words, $StopWords);
872
873 # return word array to caller
874 return $Words;
875 }
876
883 protected function CalcTextCorrelation($WordsA, $WordsB)
884 {
885 # get array containing intersection of two word arrays
886 $IntersectWords = array_intersect($WordsA, $WordsB);
887
888 # return number of words remaining as score
889 return count($IntersectWords);
890 }
891
899 protected function ContentCorrelation($ItemIdA, $ItemIdB, $NewCorrelation = -1)
900 {
901 # if item ID A is greater than item ID B
902 if ($ItemIdA > $ItemIdB)
903 {
904 # swap item IDs
905 $Temp = $ItemIdA;
906 $ItemIdA = $ItemIdB;
907 $ItemIdB = $Temp;
908 }
909
910 # if new correlation value provided
911 if ($NewCorrelation != -1)
912 {
913 # if new value is above threshold
914 if ($NewCorrelation >= $this->ContentCorrelationThreshold)
915 {
916 # insert new correlation value in DB
917 $this->DB->Query("INSERT INTO RecContentCorrelations "
918 ."(ItemIdA, ItemIdB, Correlation) "
919 ."VALUES (${ItemIdA}, ${ItemIdB}, ${NewCorrelation})");
920
921 # return correlation value is new value
922 $Correlation = $NewCorrelation;
923 }
924 # else
925 else
926 {
927 # return value is zero
928 $Correlation = 0;
929 }
930 }
931 else
932 {
933 # retrieve correlation value from DB
934 $Correlation = $this->DB->Query(
935 "SELECT Correlation FROM RecContentCorrelations "
936 ."WHERE ItemIdA = ${ItemIdA} AND ItemIdB = ${ItemIdB}",
937 "Correlation");
938
939 # if no value found in DB
940 if ($Correlation == FALSE)
941 {
942 # return value is zero
943 $Correlation = 0;
944 }
945 }
946
947 # return correlation value to caller
948 return $Correlation;
949 }
950
956 protected function FilterOnSuppliedFunctions($Results)
957 {
958 # if filter functions have been set
959 if (count($this->FilterFuncs) > 0)
960 {
961 # for each result
962 foreach ($Results as $ResourceId => $Result)
963 {
964 # for each filter function
965 foreach ($this->FilterFuncs as $FuncName)
966 {
967 # if filter protected function return TRUE for result resource
968 if ($FuncName($ResourceId))
969 {
970 # discard result
971 if ($this->DebugLevel > 2)
972 {
973 print("REC: filter callback rejected resource"
974 ." ${ResourceId}<br>\n");
975 }
976 unset($Results[$ResourceId]);
977
978 # bail out of filter func loop
979 continue 2;
980 }
981 }
982 }
983 }
984
985 # return filtered list to caller
986 return $Results;
987 }
988 }
989
Recommender\DebugLevel
DebugLevel($Setting)
Set level for debugging output.
Definition: Recommender.php:67
Recommender\RecommendFieldValues
RecommendFieldValues($ItemId, $FieldList=NULL)
Dynamically generate and return list of recommended field values for item.
Definition: Recommender.php:339
Recommender\UpdateForItems
UpdateForItems($StartingItemId, $NumberOfItems)
Update recommender data for range of items.
Definition: Recommender.php:474
Recommender\GetSourceList
GetSourceList($UserId, $RecommendedItemId)
Return list of items used to generate recommendation of specified item.
Definition: Recommender.php:228
Recommender\ContentCorrelation
ContentCorrelation($ItemIdA, $ItemIdB, $NewCorrelation=-1)
Get/set stored value for correlation between two items.
Definition: Recommender.php:899
Recommender\CONTENTFIELDTYPE_CONTROLLEDNAME
const CONTENTFIELDTYPE_CONTROLLEDNAME
Definition: Recommender.php:20
Recommender\AddResultFilterFunction
AddResultFilterFunction($FunctionName)
Add function to be called to filter returned recommendation list.
Definition: Recommender.php:195
Recommender\CONTENTFIELDTYPE_DATE
const CONTENTFIELDTYPE_DATE
Definition: Recommender.php:21
Recommender\__construct
__construct(&$DB, $ItemTableName, $RatingTableName, $ItemIdFieldName, $UserIdFieldName, $RatingFieldName, $ContentFields)
Object constructor.
Definition: Recommender.php:41
Recommender\FilterOnSuppliedFunctions
FilterOnSuppliedFunctions($Results)
Run results through supplied filter functions.
Definition: Recommender.php:956
Recommender\SearchTime
SearchTime()
Get time it took to generate the most recent recommendation.
Definition: Recommender.php:214
Recommender\PruneCorrelations
PruneCorrelations()
Prune any stored correlation values that are below-average.
Definition: Recommender.php:562
Recommender\GetItemIds
GetItemIds()
Retrieve all item IDs.
Definition: Recommender.php:580
Recommender\UpdateForItem
UpdateForItem($ItemId, $FullPass=FALSE)
Update recommender data for specified item.
Definition: Recommender.php:521
Recommender\NumberOfResults
NumberOfResults()
Get number of recommendations generated.
Definition: Recommender.php:205
Recommender\CONTENTFIELDTYPE_NUMERIC
const CONTENTFIELDTYPE_NUMERIC
Definition: Recommender.php:19
Recommender\GetFieldData
GetFieldData($ItemId, $FieldName)
Get data for field.
Definition: Recommender.php:644
Recommender\UpdateContentCorrelation
UpdateContentCorrelation($ItemIdA, $ItemIdB)
Calculate content correlation between two items and update in DB.
Definition: Recommender.php:765
PHP
PHP
Definition: RSSClient--Test.php:12
Recommender\Recommend
Recommend($UserId, $StartingResult=0, $NumberOfResults=10)
Recommend items for specified user.
Definition: Recommender.php:83
Recommender\CalcTextCorrelation
CalcTextCorrelation($WordsA, $WordsB)
Get value for correlation between two sets of words.
Definition: Recommender.php:883
Recommender\LoadItemIds
LoadItemIds()
Load internal item ID cache (if not already loaded).
Definition: Recommender.php:626
Recommender\CONTENTFIELDTYPE_TEXT
const CONTENTFIELDTYPE_TEXT
Definition: Recommender.php:18
Recommender\FindSimilarItems
FindSimilarItems($ItemId, $FieldList=NULL)
Dynamically generate and return list of items similar to specified item.
Definition: Recommender.php:271
Recommender\CONTENTFIELDTYPE_DATERAMGE
const CONTENTFIELDTYPE_DATERAMGE
Definition: Recommender.php:22
Recommender\NormalizeAndParseText
NormalizeAndParseText($Text)
Normalize text string and parse into words.
Definition: Recommender.php:785
Recommender\CalculateContentCorrelation
CalculateContentCorrelation($ItemIdA, $ItemIdB, $FieldList=NULL)
Calculate content correlation between two items and return value to caller.
Definition: Recommender.php:676
Recommender
Recommendation engine.
Definition: Recommender.php:13
Recommender\DropItem
DropItem($ItemId)
Drop item from stored recommender data.
Definition: Recommender.php:551
Recommender\ClearCaches
static ClearCaches()
Clear internal caches of item and correlation data.
Definition: Recommender.php:595