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 and tell it to cache values
84  $this->Schema = new MetadataSchema();
85  $this->Schema->CacheData(TRUE);
86 
87  # create a database connection for recommender to use
88  $DB = new Database();
89 
90  # pass configuration info to real recommender object
91  parent::__construct($DB, $ItemTableName, $RatingTableName,
92  $ItemIdFieldName, $UserIdFieldName, $RatingFieldName,
93  $FieldInfo);
94  }
95 
102  public function GetFieldValue($ItemId, $FieldName)
103  {
104  static $Resources;
105 
106  # if resource not already loaded
107  if (!isset($Resources[$ItemId]))
108  {
109  # get resource object
110  $Resources[$ItemId] = new Resource($ItemId);
111 
112  # if cached resource limit exceeded
113  if (count($Resources) > 100)
114  {
115  # dump oldest resource
116  reset($Resources);
117  list($DumpedItemId, $DumpedResources) = each($Resources);
118  unset($Resources[$DumpedItemId]);
119  }
120  }
121 
122  # retrieve field value from resource object and return to caller
123  $FieldValue = $Resources[$ItemId]->Get($FieldName);
124  return $FieldValue;
125  }
126 
133  public function QueueUpdateForItem($ItemOrItemId, $TaskPriority = NULL)
134  {
135  if (is_numeric($ItemOrItemId))
136  {
137  $ItemId = $ItemOrItemId;
138  $Item = new Resource($ItemId);
139  }
140  else
141  {
142  $Item = $ItemOrItemId;
143  $ItemId = $Item->Id();
144  }
145 
146  # if no proirity was provided, use the default
147  if ($TaskPriority === NULL)
148  {
149  $TaskPriority = self::$TaskPriority;
150  }
151 
152  $TaskDescription = "Update recommender data for"
153  ." <a href=\"r".$ItemId."\"><i>"
154  .$Item->GetMapped("Title")."</i></a>";
155  $GLOBALS["AF"]->QueueUniqueTask(array(__CLASS__, "RunUpdateForItem"),
156  array(intval($ItemId), 0), $TaskPriority);
157  }
158 
164  public static function RunUpdateForItem($SourceItemId, $StartingIndex)
165  {
166  # check that resource still exists
167  $RFactory = new ResourceFactory();
168  if (!$RFactory->ItemExists($SourceItemId)) { return; }
169 
170  # load recommender engine
171  static $Recommender;
172  if (!isset($Recommender)) { $Recommender = new SPTRecommender(); }
173 
174  # if starting update for source item
175  if ($StartingIndex == 0)
176  {
177  # clear data for item
178  $Recommender->DropItem($SourceItemId);
179  }
180 
181  # load array of item IDs and pare down to those in same schema as source item
182  $TargetItemIds = $Recommender->GetItemIds();
183  $SourceSchemaIds = $RFactory->GetItemIds();
184  $TargetItemIds = array_values(array_intersect(
185  $TargetItemIds, $SourceSchemaIds));
186  $TargetCount = count($TargetItemIds);
187 
188  # while not last item ID and not out of time
189  for ($Index = $StartingIndex; $Index < $TargetCount; $Index++)
190  {
191  # if target ID points to non-temporary entry
192  if ($TargetItemIds[$Index] >= 0)
193  {
194  # update correlation for source item and current item
195  $StartTime = microtime(TRUE);
196  $Recommender->UpdateContentCorrelation(
197  $SourceItemId, $TargetItemIds[$Index]);
198  $ExecutionTime = microtime(TRUE) - $StartTime;
199 
200  # clear all caches if memory has run low
201  if ($GLOBALS["AF"]->GetFreeMemory() < 8000000)
202  {
203  Database::Caching(FALSE);
204  Database::Caching(TRUE);
205  self::ClearCaches();
206  if (function_exists("gc_collect_cycles"))
207  {
208  gc_collect_cycles();
209  }
210  }
211 
212  # bail out if out of memory or not enough time for another update
213  if (($GLOBALS["AF"]->GetSecondsBeforeTimeout() < ($ExecutionTime * 2))
214  || ($GLOBALS["AF"]->GetFreeMemory() < 8000000))
215  {
216  break;
217  }
218  }
219  }
220 
221  # if all correlations completed for source item
222  if ($Index >= $TargetCount)
223  {
224  # periodically prune correlations if enough time remaining
225  if (($GLOBALS["AF"]->GetSecondsBeforeTimeout() > 20)
226  && (rand(1, 10) == 1))
227  {
228  $Recommender->PruneCorrelations();
229  }
230  }
231  else
232  {
233  # requeue updates for remaining items
234  $Item = new Resource($SourceItemId);
235  $TaskDescription = "Update recommender data for"
236  ." <a href=\"r".$SourceItemId."\"><i>"
237  .$Item->GetMapped("Title")."</i></a>";
238  $GLOBALS["AF"]->QueueUniqueTask(array(__CLASS__, "RunUpdateForItem"),
239  array((int)$SourceItemId, $Index),
241  }
242  }
243 
249  public static function SetUpdatePriority($NewPriority)
250  {
251  self::$TaskPriority = $NewPriority;
252  }
253 
254  # ---- PRIVATE INTERFACE -------------------------------------------------
255 
256  private $Schema;
257  private static $TaskPriority = ApplicationFramework::PRIORITY_BACKGROUND;
258 }
static Caching($NewSetting=NULL)
Get or set whether query result caching is currently enabled.
Definition: Database.php:237
Metadata schema (in effect a Factory class for MetadataField).
const PRIORITY_LOW
Lower priority.
const CONTENTFIELDTYPE_DATE
Definition: Recommender.php:18
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:16
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:15
Represents a "resource" in CWIS.
Definition: Resource.php:13
static SetUpdatePriority($NewPriority)
Set the default priority for background tasks.
Factory for Resource objects.
const PRIORITY_BACKGROUND
Lowest priority.