CWIS Developer Documentation
SPTRecommender.php
Go to the documentation of this file.
1 <?PHP
2 #
3 # FILE: SPTRecommender.php
4 #
5 # Part of the Collection Workflow Integration System (CWIS)
6 # Copyright 2011-2013 Edward Almasy and Internet Scout Research Group
7 # http://scout.wisc.edu/cwis/
8 #
9 
11 {
12 
16  public function __construct()
17  {
18  # set up recommender configuration values for SPT
19  $ItemTableName = "Resources";
20  $ItemIdFieldName = "ResourceId";
21  $RatingTableName = "ResourceRatings";
22  $UserIdFieldName = "UserId";
23  $RatingFieldName = "Rating";
24 
25  # build field info from SPT metadata schema
26  $this->Schema = new MetadataSchema();
27  $Fields = $this->Schema->GetFields();
28  foreach ($Fields as $Field)
29  {
30  if ($Field->Enabled() && $Field->IncludeInKeywordSearch())
31  {
32  $FieldName = $Field->Name();
33  $FieldInfo[$FieldName]["DBFieldName"] = $Field->DBFieldName();
34  $FieldInfo[$FieldName]["Weight"] = $Field->SearchWeight();
35  switch ($Field->Type())
36  {
41  $FieldInfo[$FieldName]["FieldType"] =
43  break;
44 
48  $FieldInfo[$FieldName]["FieldType"] =
50  break;
51 
54  $FieldInfo[$FieldName]["FieldType"] =
56  break;
57 
59  $FieldInfo[$FieldName]["FieldType"] =
60  Recommender::CONTENTFIELDTYPE_DATERANGE;
61  break;
62 
64  $FieldInfo[$FieldName]["FieldType"] =
66  break;
67 
69  # (for images we use their alt text)
70  $FieldInfo[$FieldName]["FieldType"] =
72  break;
73 
75  # (for files we use the file name)
76  $FieldInfo[$FieldName]["FieldType"] =
78  break;
79  }
80  }
81  }
82 
83  # create our own schema object
84  $this->Schema = new MetadataSchema();
85 
86  # create a database connection for recommender to use
87  $DB = new Database();
88 
89  # pass configuration info to real recommender object
90  parent::__construct($DB, $ItemTableName, $RatingTableName,
91  $ItemIdFieldName, $UserIdFieldName, $RatingFieldName,
92  $FieldInfo);
93  }
94 
101  public function GetFieldValue($ItemId, $FieldName)
102  {
103  static $Resources;
104 
105  # if resource not already loaded
106  if (!isset($Resources[$ItemId]))
107  {
108  # get resource object
109  $Resources[$ItemId] = new Resource($ItemId);
110 
111  # if cached resource limit exceeded
112  if (count($Resources) > 100)
113  {
114  # dump oldest resource
115  reset($Resources);
116  list($DumpedItemId, $DumpedResources) = each($Resources);
117  unset($Resources[$DumpedItemId]);
118  }
119  }
120 
121  # retrieve field value from resource object and return to caller
122  $FieldValue = $Resources[$ItemId]->Get($FieldName);
123  return $FieldValue;
124  }
125 
132  public function QueueUpdateForItem($ItemOrItemId, $TaskPriority = NULL)
133  {
134  if (is_numeric($ItemOrItemId))
135  {
136  $ItemId = $ItemOrItemId;
137  $Item = new Resource($ItemId);
138  }
139  else
140  {
141  $Item = $ItemOrItemId;
142  $ItemId = $Item->Id();
143  }
144 
145  # if no proirity was provided, use the default
146  if ($TaskPriority === NULL)
147  {
148  $TaskPriority = self::$TaskPriority;
149  }
150 
151  $TaskDescription = "Update recommender data for"
152  ." <a href=\"r".$ItemId."\"><i>"
153  .$Item->GetMapped("Title")."</i></a>";
154  $GLOBALS["AF"]->QueueUniqueTask(array(__CLASS__, "RunUpdateForItem"),
155  array(intval($ItemId), 0), $TaskPriority, $TaskDescription);
156  }
157 
163  public static function RunUpdateForItem($SourceItemId, $StartingIndex)
164  {
165  # check that resource still exists
166  $RFactory = new ResourceFactory();
167  if (!$RFactory->ItemExists($SourceItemId)) { return; }
168 
169  # load recommender engine
170  static $Recommender;
171  if (!isset($Recommender)) { $Recommender = new SPTRecommender(); }
172 
173  # if starting update for source item
174  if ($StartingIndex == 0)
175  {
176  # clear data for item
177  $Recommender->DropItem($SourceItemId);
178  }
179 
180  # load array of item IDs and pare down to those in same schema as source item
181  $TargetItemIds = $Recommender->GetItemIds();
182  $SourceSchemaIds = $RFactory->GetItemIds();
183  $TargetItemIds = array_values(array_intersect(
184  $TargetItemIds, $SourceSchemaIds));
185  $TargetCount = count($TargetItemIds);
186 
187  # while not last item ID and not out of time
188  for ($Index = $StartingIndex; $Index < $TargetCount; $Index++)
189  {
190  # if target ID points to non-temporary entry
191  if ($TargetItemIds[$Index] >= 0)
192  {
193  # update correlation for source item and current item
194  $StartTime = microtime(TRUE);
195  $Recommender->UpdateContentCorrelation(
196  $SourceItemId, $TargetItemIds[$Index]);
197  $ExecutionTime = microtime(TRUE) - $StartTime;
198 
199  # clear all caches if memory has run low
200  if ($GLOBALS["AF"]->GetFreeMemory() < 8000000)
201  {
202  Database::Caching(FALSE);
203  Database::Caching(TRUE);
204  self::ClearCaches();
205  if (function_exists("gc_collect_cycles"))
206  {
207  gc_collect_cycles();
208  }
209  }
210 
211  # bail out if out of memory or not enough time for another update
212  if (($GLOBALS["AF"]->GetSecondsBeforeTimeout() < ($ExecutionTime * 2))
213  || ($GLOBALS["AF"]->GetFreeMemory() < 8000000))
214  {
215  break;
216  }
217  }
218  }
219 
220  # if all correlations completed for source item
221  if ($Index >= $TargetCount)
222  {
223  # periodically prune correlations if enough time remaining
224  if (($GLOBALS["AF"]->GetSecondsBeforeTimeout() > 20)
225  && (rand(1, 10) == 1))
226  {
227  $Recommender->PruneCorrelations();
228  }
229  }
230  else
231  {
232  # requeue updates for remaining items
233  $Item = new Resource($SourceItemId);
234  $TaskDescription = "Update recommender data for"
235  ." <a href=\"r".$SourceItemId."\"><i>"
236  .$Item->GetMapped("Title")."</i></a>";
237  $GLOBALS["AF"]->QueueUniqueTask(array(__CLASS__, "RunUpdateForItem"),
238  array((int)$SourceItemId, $Index),
240  }
241  }
242 
248  public static function SetUpdatePriority($NewPriority)
249  {
250  self::$TaskPriority = $NewPriority;
251  }
252 
253  # ---- PRIVATE INTERFACE -------------------------------------------------
254 
255  private $Schema;
256  private static $TaskPriority = ApplicationFramework::PRIORITY_BACKGROUND;
257 }
static Caching($NewSetting=NULL)
Get or set whether query result caching is currently enabled.
Definition: Database.php:259
Metadata schema (in effect a Factory class for MetadataField).
const PRIORITY_LOW
Lower priority.
const CONTENTFIELDTYPE_DATE
Definition: Recommender.php:21
SQL database abstraction object with smart query caching.
Definition: Database.php:22
__construct()
SPTRecommender object constructor.
GetFieldValue($ItemId, $FieldName)
Get value for a given field.
const CONTENTFIELDTYPE_NUMERIC
Definition: Recommender.php:19
const MDFTYPE_CONTROLLEDNAME
static RunUpdateForItem($SourceItemId, $StartingIndex)
Perform recommender db updates for a specified item (usually in the background)
QueueUpdateForItem($ItemOrItemId, $TaskPriority=NULL)
Queue a background update for a specified item.
const CONTENTFIELDTYPE_TEXT
Definition: Recommender.php:18
Represents a "resource" in CWIS.
Definition: Resource.php:13
static SetUpdatePriority($NewPriority)
Set the default priority for background tasks.
Recommendation engine.
Definition: Recommender.php:13
Factory for Resource objects.
const PRIORITY_BACKGROUND
Lowest priority.