3 # FILE: SPTSearchEngine.php 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/ 17 # pass database handle and config values to real search engine object 18 parent::__construct(
"Resources",
"ResourceId",
"SchemaId");
22 foreach ($Schemas as $SchemaId => $Schema)
24 # for each field defined in schema 26 $Fields = $this->Schemas[$SchemaId]->GetFields();
27 foreach ($Fields as $FieldId => $Field)
29 # save metadata field type 30 $this->FieldTypes[$FieldId] = $Field->Type();
32 # determine field type for searching 33 switch ($Field->Type())
45 $FieldType = self::FIELDTYPE_TEXT;
50 $FieldType = self::FIELDTYPE_NUMERIC;
54 $FieldType = self::FIELDTYPE_DATERANGE;
58 $FieldType = self::FIELDTYPE_DATE;
66 throw Exception(
"ERROR: unknown field type " 71 if ($FieldType !== NULL)
73 # add field to search engine 74 $this->
AddField($FieldId, $FieldType, $Field->SchemaId(),
75 $Field->SearchWeight(),
76 $Field->IncludeInKeywordSearch());
94 # if this is a reference field 97 # retrieve IDs of referenced items 98 $ReferredItemIds = $Resource->Get($FieldId);
100 # for each referred item 101 $ReturnValue = array();
102 foreach ($ReferredItemIds as $RefId)
104 # retrieve title value for item and add to returned values 105 $RefResource =
new Resource($RefId);
106 $ReturnValue[] = $RefResource->GetMapped(
"Title");
109 # return referred item titles to caller 114 # retrieve text (including variants) from resource object and return to caller 115 return $Resource->Get($FieldId, FALSE, TRUE);
127 # normalize and escape search phrase for use in SQL query 128 $SearchPhrase = strtolower(addslashes($Phrase));
130 # query DB for matching list based on field type 132 switch ($Field->Type())
138 $QueryString =
"SELECT DISTINCT ResourceId FROM Resources " 139 .
"WHERE POSITION('".$SearchPhrase.
"'" 140 .
" IN LOWER(`".$Field->DBFieldName().
"`)) ";
144 $QueryString =
"SELECT DISTINCT ResourceId FROM Resources " 145 .
"WHERE POSITION('".$SearchPhrase.
"'" 146 .
" IN LOWER(`".$Field->DBFieldName().
"AltText`)) ";
150 $NameTableSize = $this->DB->Query(
"SELECT COUNT(*) AS NameCount" 151 .
" FROM ControlledNames",
"NameCount");
152 $QueryString =
"SELECT DISTINCT ResourceNameInts.ResourceId " 153 .
"FROM ResourceNameInts, ControlledNames " 154 .
"WHERE POSITION('".$SearchPhrase.
"' IN LOWER(ControlledName)) " 155 .
"AND ControlledNames.ControlledNameId" 156 .
" = ResourceNameInts.ControlledNameId " 157 .
"AND ControlledNames.FieldId = ".intval($FieldId);
158 $SecondQueryString =
"SELECT DISTINCT ResourceNameInts.ResourceId " 159 .
"FROM ResourceNameInts, ControlledNames, VariantNames " 160 .
"WHERE POSITION('".$SearchPhrase.
"' IN LOWER(VariantName)) " 161 .
"AND VariantNames.ControlledNameId" 162 .
" = ResourceNameInts.ControlledNameId " 163 .
"AND ControlledNames.ControlledNameId" 164 .
" = ResourceNameInts.ControlledNameId " 165 .
"AND ControlledNames.FieldId = ".intval($FieldId);
169 $QueryString =
"SELECT DISTINCT ResourceNameInts.ResourceId " 170 .
"FROM ResourceNameInts, ControlledNames " 171 .
"WHERE POSITION('".$SearchPhrase.
"' IN LOWER(ControlledName)) " 172 .
"AND ControlledNames.ControlledNameId" 173 .
" = ResourceNameInts.ControlledNameId " 174 .
"AND ControlledNames.FieldId = ".intval($FieldId);
178 $QueryString =
"SELECT DISTINCT ResourceClassInts.ResourceId " 179 .
"FROM ResourceClassInts, Classifications " 180 .
"WHERE POSITION('".$SearchPhrase
181 .
"' IN LOWER(ClassificationName)) " 182 .
"AND Classifications.ClassificationId" 183 .
" = ResourceClassInts.ClassificationId " 184 .
"AND Classifications.FieldId = ".intval($FieldId);
188 $UserId = $this->DB->Query(
"SELECT UserId FROM APUsers " 189 .
"WHERE POSITION('".$SearchPhrase
190 .
"' IN LOWER(UserName)) " 191 .
"OR POSITION('".$SearchPhrase
192 .
"' IN LOWER(RealName))",
"UserId");
195 $QueryString =
"SELECT DISTINCT ResourceId FROM ResourceUserInts " 196 .
"WHERE UserId = ".$UserId
197 .
" AND FieldId = ".intval($FieldId);
202 if ($SearchPhrase > 0)
204 $QueryString =
"SELECT DISTINCT ResourceId FROM Resources " 205 .
"WHERE `".$Field->DBFieldName()
206 .
"` = ".(int)$SearchPhrase;
214 # (these types not yet handled by search engine for phrases) 218 # build match list based on results returned from DB 219 if (isset($QueryString))
221 $this->
DMsg(7,
"Performing phrase search query (<i>".$QueryString.
"</i>)");
222 if ($this->
DebugLevel > 9) { $StartTime = microtime(TRUE); }
223 $this->DB->Query($QueryString);
226 $EndTime = microtime(TRUE);
227 if (($StartTime - $EndTime) > 0.1)
229 printf(
"SE: Query took %.2f seconds<br>\n",
230 ($EndTime - $StartTime));
233 $MatchList = $this->DB->FetchColumn(
"ResourceId");
234 if (isset($SecondQueryString))
236 $this->
DMsg(7,
"Performing second phrase search query" 237 .
" (<i>".$SecondQueryString.
"</i>)");
238 if ($this->
DebugLevel > 9) { $StartTime = microtime(TRUE); }
239 $this->DB->Query($SecondQueryString);
242 $EndTime = microtime(TRUE);
243 if (($StartTime - $EndTime) > 0.1)
245 printf(
"SE: query took %.2f seconds<br>\n",
246 ($EndTime - $StartTime));
249 $MatchList = $MatchList + $this->DB->FetchColumn(
"ResourceId");
254 $MatchList = array();
257 # return list of matching resources to caller 270 $FieldIds, $Operators, $Values, $Logic)
272 # use SQL keyword appropriate to current search logic for combining operations 273 $CombineWord = ($Logic ==
"AND") ?
" AND " :
" OR ";
275 # for each comparison 276 foreach ($FieldIds as $Index => $FieldId)
278 $Operator = $Operators[$Index];
279 $Value = $Values[$Index];
284 switch ($Field->Type())
291 if (isset($Queries[
"Resources"]))
293 $Queries[
"Resources"] .= $CombineWord;
297 $Queries[
"Resources"] =
"SELECT DISTINCT ResourceId" 298 .
" FROM Resources WHERE ";
300 $Queries[
"Resources"] .= $this->GetTextComparisonSql(
301 $Field->DBFieldName(), $Operator, $Value);
305 $QueryIndex =
"ResourceUserInts".$FieldId;
307 if (isset($Queries[$QueryIndex]))
309 $Queries[$QueryIndex] .= $CombineWord;
313 $Queries[$QueryIndex] =
"SELECT DISTINCT ResourceId" 314 .
" FROM ResourceUserInts WHERE ";
317 $User =
new CWUser($Value);
319 $Queries[$QueryIndex] .=
320 "(UserId = ".$User->Id().
" AND FieldId = " 321 .intval($FieldId).
")";
325 $QueryIndex =
"ResourceNameInts".$Field->Id();
326 if (!isset($Queries[$QueryIndex][
"A"]))
328 $Queries[$QueryIndex][
"A"] =
329 "SELECT DISTINCT ResourceId" 330 .
" FROM ResourceNameInts, ControlledNames " 331 .
" WHERE ControlledNames.FieldId = " 334 $CloseQuery[$QueryIndex][
"A"] = TRUE;
335 $ComparisonCount[$QueryIndex][
"A"] = 1;
336 $ComparisonCountField[$QueryIndex][
"A"] =
"ControlledName";
340 $Queries[$QueryIndex][
"A"] .=
" OR ";
341 $ComparisonCount[$QueryIndex][
"A"]++;
343 $Queries[$QueryIndex][
"A"] .=
344 "(ResourceNameInts.ControlledNameId" 345 .
" = ControlledNames.ControlledNameId" 346 .
" AND ".$this->GetTextComparisonSql(
347 "ControlledName", $Operator, $Value)
349 if (!isset($Queries[$QueryIndex][
"B"]))
351 $Queries[$QueryIndex][
"B"] =
352 "SELECT DISTINCT ResourceId" 353 .
" FROM ResourceNameInts, ControlledNames," 355 .
" WHERE ControlledNames.FieldId = " 356 .intval($Field->Id())
358 $CloseQuery[$QueryIndex][
"B"] = TRUE;
359 $ComparisonCount[$QueryIndex][
"B"] = 1;
360 $ComparisonCountField[$QueryIndex][
"B"] =
"ControlledName";
364 $Queries[$QueryIndex][
"B"] .=
" OR ";
365 $ComparisonCount[$QueryIndex][
"B"]++;
367 $Queries[$QueryIndex][
"B"] .=
368 "(ResourceNameInts.ControlledNameId" 369 .
" = ControlledNames.ControlledNameId" 370 .
" AND ResourceNameInts.ControlledNameId" 371 .
" = VariantNames.ControlledNameId" 372 .
" AND ".$this->GetTextComparisonSql(
373 "VariantName", $Operator, $Value)
378 $QueryIndex =
"ResourceNameInts".$FieldId;
379 if (!isset($Queries[$QueryIndex]))
381 $Queries[$QueryIndex] =
382 "SELECT DISTINCT ResourceId" 383 .
" FROM ResourceNameInts, ControlledNames " 384 .
" WHERE ControlledNames.FieldId = " 387 $CloseQuery[$QueryIndex] = TRUE;
388 $ComparisonCount[$QueryIndex] = 1;
389 $ComparisonCountField[$QueryIndex] =
"ControlledName";
393 $Queries[$QueryIndex] .=
" OR ";
394 $ComparisonCount[$QueryIndex]++;
396 $Queries[$QueryIndex] .=
397 "(ResourceNameInts.ControlledNameId" 398 .
" = ControlledNames.ControlledNameId" 399 .
" AND ".$this->GetTextComparisonSql(
400 "ControlledName", $Operator, $Value)
405 $QueryIndex =
"ResourceClassInts".$FieldId;
406 if (!isset($Queries[$QueryIndex]))
408 $Queries[$QueryIndex] =
"SELECT DISTINCT ResourceId" 409 .
" FROM ResourceClassInts, Classifications" 410 .
" WHERE ResourceClassInts.ClassificationId" 411 .
" = Classifications.ClassificationId" 412 .
" AND Classifications.FieldId" 413 .
" = ".intval($FieldId).
" AND ( ";
414 $CloseQuery[$QueryIndex] = TRUE;
415 $ComparisonCount[$QueryIndex] = 1;
416 $ComparisonCountField[$QueryIndex] =
"ClassificationName";
420 $Queries[$QueryIndex] .=
" OR ";
421 $ComparisonCount[$QueryIndex]++;
423 $Queries[$QueryIndex] .= $this->GetTextComparisonSql(
424 "ClassificationName", $Operator, $Value);
428 # if value appears to have time component or text description 429 if (strpos($Value,
":")
430 || strstr($Value,
"day")
431 || strstr($Value,
"week")
432 || strstr($Value,
"month")
433 || strstr($Value,
"year")
434 || strstr($Value,
"hour")
435 || strstr($Value,
"minute"))
437 if (isset($Queries[
"Resources"]))
439 $Queries[
"Resources"] .= $CombineWord;
443 $Queries[
"Resources"] =
"SELECT DISTINCT ResourceId" 444 .
" FROM Resources WHERE ";
447 # flip operator if necessary 448 if (strstr($Value,
"ago"))
450 $OperatorFlipMap = array(
456 $Operator = isset($OperatorFlipMap[$Operator])
457 ? $OperatorFlipMap[$Operator] : $Operator;
460 # use strtotime method to build condition 461 $TimestampValue = strtotime($Value);
462 if (($TimestampValue !== FALSE) && ($TimestampValue != -1))
464 if ((date(
"H:i:s", $TimestampValue) ==
"00:00:00")
465 && (strpos($Value,
"00:00") === FALSE)
466 && ($Operator ==
"<="))
469 date(
"Y-m-d", $TimestampValue).
" 23:59:59";
473 $NormalizedValue = date(
474 "Y-m-d H:i:s", $TimestampValue);
479 $NormalizedValue = addslashes($Value);
481 $Queries[
"Resources"] .=
482 " ( `".$Field->DBFieldName().
"` " 484 .
" '".$NormalizedValue.
"' ) ";
488 # use Date object method to build condition 489 $Date =
new Date($Value);
490 if ($Date->Precision())
492 if (isset($Queries[
"Resources"]))
494 $Queries[
"Resources"] .= $CombineWord;
498 $Queries[
"Resources"] =
"SELECT DISTINCT ResourceId" 499 .
" FROM Resources WHERE ";
501 $Queries[
"Resources"] .=
" ( ".$Date->SqlCondition(
502 $Field->DBFieldName(), NULL, $Operator).
" ) ";
508 $Date =
new Date($Value);
509 if ($Date->Precision())
511 if (isset($Queries[
"Resources"]))
513 $Queries[
"Resources"] .= $CombineWord;
517 $Queries[
"Resources"] =
"SELECT DISTINCT ResourceId" 518 .
" FROM Resources WHERE ";
520 $Queries[
"Resources"] .=
" ( ".$Date->SqlCondition(
521 $Field->DBFieldName().
"Begin",
522 $Field->DBFieldName().
"End", $Operator).
" ) ";
527 $QueryIndex =
"ReferenceInts".$FieldId;
528 if (!isset($Queries[$QueryIndex]))
530 $Queries[$QueryIndex] =
531 "SELECT DISTINCT RI.SrcResourceId AS ResourceId" 532 .
" FROM ReferenceInts AS RI, Resources AS R " 533 .
" WHERE RI.FieldId = ".intval($FieldId)
535 $CloseQuery[$QueryIndex] = TRUE;
539 $Queries[$QueryIndex] .= $CombineWord;
542 # iterate over all the schemas this field can reference, 543 # gluing together an array of subqueries for the mapped 544 # title field of each as we go 545 $SchemaIds = $Field->ReferenceableSchemaIds();
547 # if no referenceable schemas configured, fall back to 548 # searching all schemas 549 if (count($SchemaIds)==0)
554 $Subqueries = array();
555 foreach ($SchemaIds as $SchemaId)
558 $MappedTitle = $Schema->GetFieldByMappedName(
"Title");
560 $Subqueries[]= $this->GetTextComparisonSql(
561 $MappedTitle->DBFieldName(), $Operator, $Value,
"R");
564 # OR together all the subqueries, add it to the query 566 $Queries[$QueryIndex] .=
567 "((".implode(
" OR ", $Subqueries).
")" 568 .
" AND R.ResourceId = RI.DstResourceId)";
573 # (these types not yet handled by search engine for comparisons) 582 # for each assembled query 583 foreach ($Queries as $QueryIndex => $Query)
585 # if query has multiple parts 586 if (is_array($Query))
588 # for each part of query 589 $ResourceIds = array();
590 foreach ($Query as $PartIndex => $PartQuery)
592 # add closing paren if query was flagged to be closed 593 if (isset($CloseQuery[$QueryIndex][$PartIndex]))
596 if (($Logic ==
"AND")
597 && ($ComparisonCount[$QueryIndex][$PartIndex] > 1))
599 $PartQuery .=
"GROUP BY ResourceId" 600 .
" HAVING COUNT(DISTINCT " 601 .$ComparisonCountField[$QueryIndex][$PartIndex]
603 .$ComparisonCount[$QueryIndex][$PartIndex];
607 # perform query and retrieve IDs 608 $this->
DMsg(5,
"Performing comparison query <i>" 610 $this->DB->Query($PartQuery);
611 $ResourceIds = $ResourceIds
612 + $this->DB->FetchColumn(
"ResourceId");
613 $this->
DMsg(5,
"Comparison query produced <i>" 614 .count($ResourceIds).
"</i> results");
619 # add closing paren if query was flagged to be closed 620 if (isset($CloseQuery[$QueryIndex]))
623 if (($Logic ==
"Logic")
624 && ($ComparisonCount[$QueryIndex] > 1))
626 $Query .=
"GROUP BY ResourceId" 627 .
" HAVING COUNT(DISTINCT " 628 .$ComparisonCountField[$QueryIndex]
630 .$ComparisonCount[$QueryIndex];
634 # perform query and retrieve IDs 635 $this->
DMsg(5,
"Performing comparison query <i>".$Query.
"</i>");
636 $this->DB->Query($Query);
637 $ResourceIds = $this->DB->FetchColumn(
"ResourceId");
638 $this->
DMsg(5,
"Comparison query produced <i>" 639 .count($ResourceIds).
"</i> results");
642 # if we already have some results 645 # if search logic is set to AND 648 # remove anything from results that was not returned from query 649 $Results = array_intersect($Results, $ResourceIds);
653 # add values returned from query to results 654 $Results = array_unique(array_merge($Results, $ResourceIds));
659 # set results to values returned from query 660 $Results = $ResourceIds;
666 # initialize results to empty list 670 # return results to caller 683 $ItemType, $FieldId, $SortDescending)
686 return $RFactory->GetResourceIdsSortedBy($FieldId, !$SortDescending);
697 if (is_numeric($ItemOrItemId))
699 $ItemId = $ItemOrItemId;
704 $Item = $ItemOrItemId;
705 $ItemId = $Item->Id();
708 # if no priority was provided, use the default 709 if ($TaskPriority === NULL)
711 $TaskPriority = self::$TaskPriority;
714 # assemble task description 715 $Title = $Item->GetMapped(
"Title");
718 $Title =
"Item #".$ItemId;
720 $TaskDescription =
"Update search data for" 721 .
" <a href=\"r".$ItemId.
"\"><i>" 725 $GLOBALS[
"AF"]->QueueUniqueTask(array(__CLASS__,
"RunUpdateForItem"),
726 array(intval($ItemId)), $TaskPriority, $TaskDescription);
735 # bail out if item no longer exists 737 if ($Resource->Status() == -1) {
return; }
739 # bail out if item is a temporary record 740 if ($Resource->IsTempResource()) {
return; }
742 # retrieve schema ID of item to use for item type 743 $ItemType = $Resource->SchemaId();
745 # update search data for resource 747 $SearchEngine->UpdateForItem($ItemId, $ItemType);
760 # classifications and names associated with these search results 761 $SearchClasses = array();
762 $SearchNames = array();
764 # make sure we're not faceting too many resources 765 $SearchResults = array_slice(
767 self::$NumResourcesForFacets,
770 # disable DB cache for the search suggestions process, 771 # this avoids memory exhaustion. 775 # number of resources to include in a chunk 776 # a mysql BIGINT is at most 21 characters long and the 777 # default max_packet_size is 1 MiB, so we can pack about 778 # 1 MiB / (22 bytes) = 47,663 ResourceIds into a query before 779 # we need to worry about length problems 782 if (count($SearchResults)>0)
784 foreach (array_chunk($SearchResults, $ChunkSize, TRUE) as $Chunk)
786 # pull out all the Classifications that were associated 787 # with our search results along with all their parents 788 $DB->Query(
"SELECT ResourceId,ClassificationId FROM ResourceClassInts " 789 .
"WHERE ResourceId IN " 790 .
"(".implode(
",", array_keys($Chunk)).
")");
791 $Rows =
$DB->FetchRows();
792 foreach ($Rows as $Row)
794 $CurId = $Row[
"ClassificationId"];
795 while ($CurId !== FALSE)
797 $SearchClasses[$CurId][]=$Row[
"ResourceId"] ;
798 $CurId = self::FindParentClass($CurId);
802 # also pull out controlled names 803 $DB->Query(
"SELECT ResourceId,ControlledNameId FROM ResourceNameInts " 804 .
"WHERE ResourceId in " 805 .
"(".implode(
",", array_keys($Chunk)).
")");
806 $Rows =
$DB->FetchRows();
807 foreach ($Rows as $Row)
809 $SearchNames[$Row[
"ControlledNameId"]][]= $Row[
"ResourceId"];
813 # make sure we haven't double-counted resources that have 814 # a classification and some of its children assigned 815 $TmpClasses = array();
816 foreach ($SearchClasses as $ClassId => $Resources)
818 $TmpClasses[$ClassId] = array_unique($Resources);
820 $SearchClasses = $TmpClasses;
823 # generate a map of FieldId -> Field Names for all of the generated facets: 824 $SuggestionsById = array();
826 # pull relevant Classification names out of the DB 827 if (count($SearchClasses)>0)
829 foreach (array_chunk($SearchClasses, $ChunkSize, TRUE) as $Chunk)
831 $DB->Query(
"SELECT FieldId,ClassificationId,ClassificationName" 832 .
" FROM Classifications" 833 .
" WHERE ClassificationId" 834 .
" IN (".implode(
",", array_keys($Chunk)).
")");
835 foreach (
$DB->FetchRows() as $Row)
837 $SuggestionsById[$Row[
"FieldId"]][]=
838 array(
"Id" => $Row[
"ClassificationId"],
839 "Name" => $Row[
"ClassificationName"],
841 $SearchClasses[$Row[
"ClassificationId"]]));
846 # pull relevant ControlledNames out of the DB 847 if (count($SearchNames)>0)
849 foreach (array_chunk($SearchNames, $ChunkSize, TRUE) as $Chunk)
851 $DB->Query(
"SELECT FieldId,ControlledNameId,ControlledName" 852 .
" FROM ControlledNames" 853 .
" WHERE ControlledNameId" 854 .
" IN (".implode(
",", array_keys($SearchNames)).
")");
855 foreach (
$DB->FetchRows() as $Row)
857 $SuggestionsById[$Row[
"FieldId"]][]=
858 array(
"Id" => $Row[
"ControlledNameId"],
859 "Name" => $Row[
"ControlledName"],
861 $SearchNames[$Row[
"ControlledNameId"]]));
866 # translate the suggestions that we have in terms of the 867 # FieldIds to suggestions in terms of the field names 868 $SuggestionsByFieldName = array();
870 # if we have suggestions to offer 871 if (count($SuggestionsById)>0)
873 # gill in an array that maps FieldNames to search links 874 # which would be appropriate for that field 875 foreach ($SuggestionsById as $FieldId => $FieldValues)
881 catch (Exception $Exception)
886 # bail on fields that didn't exist and on fields that the 887 # current user cannot view, and on fields that are 888 # disabled for advanced searching 889 if (is_object($ThisField) &&
891 $ThisField->IncludeInFacetedSearch() &&
892 $ThisField->Enabled() &&
893 $User->HasPriv($ThisField->ViewingPrivileges()))
895 $SuggestionsByFieldName[$ThisField->Name()] = array();
897 foreach ($FieldValues as $Value)
899 $SuggestionsByFieldName[$ThisField->Name()][$Value[
"Id"]] =
900 array(
"Name" => $Value[
"Name"],
"Count" => $Value[
"Count"] );
906 ksort($SuggestionsByFieldName);
908 return $SuggestionsByFieldName;
927 self::$TaskPriority = $NewPriority;
936 self::$NumResourcesForFacets = $NumToUse;
939 # ---- BACKWARD COMPATIBILITY -------------------------------------------- 961 $SearchGroups, $StartingResult = 0, $NumberOfResults = 10,
962 $SortByField = NULL, $SortDescending = TRUE)
966 # if search parameter set was passed in, use it directly 967 $SearchParams = $SearchGroups;
971 # otherwise, convert legacy array into SearchParameterSet 972 $SearchParams =
new SearchParameterSet();
973 $SearchParams->SetFromLegacyArray($SearchGroups);
978 $SearchParams, $StartingResult, $NumberOfResults,
979 $SortByField, $SortDescending);
981 # pull out the resoults for the Resource schema 1002 # create display parameters, used to make a more user-friendly 1003 # version of the search 1006 # copy keyword searches as is 1007 $DisplayParams->AddParameter(
1008 $SearchParams->GetKeywordSearchStrings() );
1010 # copy field searches as is 1011 $SearchStrings = $SearchParams->GetSearchStrings();
1012 foreach ($SearchStrings as $FieldId => $Params)
1014 $DisplayParams->AddParameter($Params, $FieldId);
1017 # iterate over the search groups, looking for the 'is or begins 1018 # with' group that we add when faceting 1019 $Groups = $SearchParams->GetSubgroups();
1020 foreach ($Groups as $Group)
1022 # if this group uses OR logic for a single field 1023 if ($Group->Logic() ==
"OR" &&
1024 count($Group->GetFields()) == 1)
1026 # pull out the search strings for this field 1027 $SearchStrings = $Group->GetSearchStrings();
1028 $FieldId = key($SearchStrings);
1029 $Values = current($SearchStrings);
1031 # check if this field is valid anywhere 1035 # if this is a tree field, and we're doing a prefix match 1036 # on it, we'll just want to display this subgroup as an "IS" 1037 # otherwise display the group unmodified 1039 preg_match(
'/^=(.*)$/', $Values[0], $FirstMatch) &&
1040 preg_match(
'/^\\^(.*) -- $/', $Values[1], $SecondMatch) &&
1041 $FirstMatch[1] == $SecondMatch[1] )
1043 $DisplayParams->AddParameter(
"=".$FirstMatch[1], $FieldId);
1047 $DisplayParams->AddSet($Group);
1053 # otherwise, just attempt to include the group as-is 1056 $DisplayParams->AddSet($Group);
1058 catch (Exception $e)
1060 # if group could not be added for any reason, continue 1065 return $DisplayParams;
1068 # ---- PRIVATE INTERFACE ------------------------------------------------- 1070 private $FieldTypes;
1073 private static $TaskPriority = ApplicationFramework::PRIORITY_BACKGROUND;
1074 private static $NumResourcesForFacets = 500;
1084 private function GetTextComparisonSql($DBField, $Operator, $Value, $Prefix=
"")
1086 # if we were given a prefix, add the necessary period so we can use it 1087 if (strlen($Prefix))
1089 $Prefix = $Prefix.
".";
1092 if ($Operator ==
"^")
1094 $EscapedValue = str_replace(
1097 addslashes($Value));
1098 $Comparison = $Prefix.
"`".$DBField.
"` LIKE '".$EscapedValue.
"%' ";
1100 elseif ($Operator ==
'$')
1102 $EscapedValue = str_replace(
1105 addslashes($Value));
1106 $Comparison = $Prefix.
"`".$DBField.
"` LIKE '%".$EscapedValue.
"' ";
1108 elseif ($Operator ==
'!=')
1111 "(".$Prefix.
"`".$DBField.
"` ".$Operator.
" '".addslashes($Value).
"'" 1112 .
" AND ".$Prefix.
"`".$DBField.
"` IS NOT NULL)";
1116 $Comparison = $Prefix.
"`".$DBField.
"` " 1117 .$Operator.
" '".addslashes($Value).
"' ";
1129 private static function FindParentClass($ClassId)
1133 # first time through, fetch the mapping of parent values we need 1134 if (!isset($ParentMap))
1138 # result here will be a parent/child mapping for all used 1139 # classifications; avoid caching it as it can be quite large 1140 $PreviousSetting =
$DB->Caching();
1141 $DB->Caching(FALSE);
1143 "SELECT ParentId, ClassificationId FROM Classifications " 1144 .
"WHERE DEPTH > 0 AND FullResourceCount > 0 " 1145 .
"AND FieldId IN (SELECT FieldId FROM MetadataFields " 1146 .
" WHERE IncludeInFacetedSearch=1)" 1148 $DB->Caching($PreviousSetting);
1150 $ParentMap =
$DB->FetchColumn(
"ParentId",
"ClassificationId");
1153 return isset($ParentMap[$ClassId]) ? $ParentMap[$ClassId] : FALSE;
AddField($FieldId, $FieldType, $ItemTypes, $Weight, $UsedInKeywordSearch)
Add field to include in searching.
Set of parameters used to perform a search.
static SetUpdatePriority($NewPriority)
Set the default priority for background tasks.
SQL database abstraction object with smart query caching.
static SetNumResourcesForFacets($NumToUse)
Set the number of resources used for search facets.
UpdateForResource($ItemId)
Compat function for old SPT code to update resources.
UpdateForItem($ItemId, $ItemType)
Update search database for the specified item.
static GetItemIdsSortedByField($ItemType, $FieldId, $SortDescending)
Return item IDs sorted by a specified field.
static RunUpdateForItem($ItemId)
Update search index for an item.
GroupedSearch($SearchGroups, $StartingResult=0, $NumberOfResults=10, $SortByField=NULL, $SortDescending=TRUE)
Perform search with logical groups of fielded searches.
SearchFieldForPhrases($FieldId, $Phrase)
Perform phrase searching.
Search($SearchParams, $StartingResult=0, $NumberOfResults=PHP_INT_MAX, $SortByField=NULL, $SortDescending=TRUE)
Perform search with specified parameters.
DMsg($Level, $Msg)
Print debug message if level set high enough.
Represents a "resource" in CWIS.
static GetResultFacets($SearchResults, $User)
Generate a list of suggested additional search terms that can be used for faceted searching...
GetFieldContent($ItemId, $FieldId)
Overloaded version of method to retrieve text from DB.
Core metadata archive search engine class.
static ConvertToDisplayParameters($SearchParams)
Get a simplified SearchParameterSet for display purposes.
SearchFieldsForComparisonMatches($FieldIds, $Operators, $Values, $Logic)
Perform comparison searches.
DebugLevel($NewValue)
Set debug output level.
Factory for Resource objects.
CWIS-specific user class.
__construct()
Class constructor.
static QueueUpdateForItem($ItemOrItemId, $TaskPriority=NULL)
Queue background update for an item.