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