Advanced Item Search Manager
Advanced Item Search Manager
The advanced item search manager (AISM) gives the developer more control over how the search indexes are traversed. This document will describe the AISM methods and provide some examples.
The first time you search on your UltraCart account it will return zero results. A background process will build the underlying indexes of your items within 30 minutes.
Â
We're going to walk you through creating a search page for your catalog. Â
- It's going to be complex, but it's necessarily complex. Â Â
- Take it slow, and read the source code comments. Â Â
- When changing velocity code, make small changes, test, repeat. Â
- Changing a large chunk of velocity code all at once is a recipe for frustration.
Â
In our example, I'll be using some sample data from an UltraCart merchant, Jon from Performance Systems Integration, who was one of the first merchants to use the advanced item search.
Steps
- Create your item attributes
- Create your catalog template
- Map the template to your desired url.
Â
Step 1: Create Item Attributes
Jon started with a matrix listing out the attributes relating to each item in one of his product categories Harnesses (automotive parts). The matrix contained almost four dozen items and seven attributes. Â
Â
From that matrix, Jon created a spreadsheet (psi_attributes.csv) that could be imported into UltraCart, defining catalog attributes for each item according to the matrix above, which he saved as a .csv file.
Â
The item import may be found here:
Home → Items → Batch Item Import
By using the spreadsheet column headers he did, Jon easily imported the file because the import wizard was able to automatically match the attribute columns to the proper field names. Â Sure beats manually assigning 20 columns.
Â
A cursory review of some items confirms the attributes were successfully loaded into the system.
Â
Â
Step 2: Create Catalog Template
The next step is to create the template file.
Navigate to:
Home → Catalog → Manage Catalog Templates
and create a new template file.
Â
At first glance of the code below, you might be a little overwhelmed. There's quite a few looping blocks, which can lead one to quickly become lost.
Here's what you need to do if you wish to use the code below:
- Line 43: Change
$attributeNames
to be a list of your attributes. - Line 53: Change
$attributeChoices
to contain your attributes and possible choices. - Line 67: Change
$attributeSelections
to also be a list of your attributes
Also:
- The outputting of the results at the end is done with a simple table (lines 207-215). After that there is some commented out code (lines 216-251) showing a more complex search results.
- Change the Look & Feel (and title). The search code has BEGIN and END comments to help you find where it starts and ends. The stuff outside of it is just markup. Change it to whatever you need.
That's it. At the minimum, changing the values of just 3 variables should make the code below work for you.
Â
Here is the file (also attached: harness_search.vm) Â It is heavily commented, so please read through it carefully.
Â
Â
Â
Step 3: Map template to url
Once the template was created, all that was left was to map it to a url.  This was done in the  Home → Catalog → Manage Catalog Groups
Â
Â
Reference
Context
The AISM object that you will interact with on your catalog page is referenced by:
Â
$advancedItemSearchManager
Methods
The AISM has a large number of methods on it that are used to build up the query and then execute it. Below are the methods on the object.
Method Group | Method Signature | Notes |
---|---|---|
Management | void resetManager() | Clears all the settings inside of the search manager to prepare for another query. |
 |  |  |
Direct Matching | AdvancedItemSearchManager actualSearch(String actualSearch) | Set the text of the actual search query entered by the user to check if they entered a direct item id. |
 | AdvancedItemSearchManager singleResultDirectMatch(boolean singleResultDirectMatch) | If the actual search matches the item id or manufacturer SKU for a result then return a single result. |
 |  |  |
Term Modifiers | AdvancedItemSearchManager resetModifiers() | Reset the modifiers for the next search term. |
 | AdvancedItemSearchManager boost(String boost) | Set the boost for the search term if there is a match. Effects the ordering of results. |
 | AdvancedItemSearchManager fuzzy(Boolean fuzzy) | Make search terms fuzzy. |
 | AdvancedItemSearchManager required(Boolean required) | Make the next operation in the search query required |
 | AdvancedItemSearchManager searchEachWord(boolean searchEachWord) | If multiple words are provided in the next term then break them up and search each one. |
 | AdvancedItemSearchManager similarity(String similarity) | Set the similarity for search terms. |
 | AdvancedItemSearchManager wildcard(Boolean wildcard) | Make search terms a wildcard search. |
 |  |  |
Terms | AdvancedItemSearchManager attribute(String attributeName, String term) | Search a specific attribute for a term. |
 | AdvancedItemSearchManager attributes(String term) | Search all attributes for a term |
 | AdvancedItemSearchManager barcode(String term) | Search the barcode field |
 | AdvancedItemSearchManager cost(String comparison, String value) | Search the cost field. Valid values for the comparison parameter are:
|
 | AdvancedItemSearchManager costBetween(String valueLow, String valueHigh) | Search the cost field to find items between a range. |
 | AdvancedItemSearchManager description(String term) | Search the description field |
 | AdvancedItemSearchManager extendedDescription(String term) | Search the extended description field. |
 | AdvancedItemSearchManager itemId(String term) | Search the item id field. |
 | AdvancedItemSearchManager manufacturerName(String term) | Search the manufacturer name field. |
 | AdvancedItemSearchManager manufacturerSKU(String term) | Search the manufacturer SKU field. |
 | AdvancedItemSearchManager simple(String search) | Performs a "simple" search which is the same behavior that the regular built in search engine of UltraCart uses. |
 | AdvancedItemSearchManager simple(String search, boolean expanded) | Performs a "simple" search which is the same behavior that the regular built in search engine of UltraCart uses, but expand the results further with fuzzy logic. |
 |  |  |
 | AdvancedItemSearchManager openGroup() | Opens a logic group (think open parenthesis in a programming language) |
 | AdvancedItemSearchManager closeGroup() | Closes a logic group (think closing parenthesis in a programming language) |
 | AdvancedItemSearchManager and() | Separate terms or groups with an AND operation. |
 | AdvancedItemSearchManager or() | Separate terms or groups with an OR operation. |
 |  |  |
Convenience | void noop() | Consumes the output of the last daisy chained method call to make sure nothing outputs from the Velocity rendering. |
 |  |  |
Search | AdvancedItemSearchResult search() | Returns up to 50 results |
 | AdvancedItemSearchResult search(int pageNumber) | Returns specific page number of results with 50 items per page. |
 | AdvancedItemSearchResult search(int pageNumber, int itemsPerPage) | Return specific page number of results with up to 200 items per page. |
Â
Results
The search methods return an AdvancedItemSearchResult object. This object contains a child array of AdvancedItemSearchResultRecord which ultimately contains the catalog Item objects. Below is the object method for each result object.
AdvancedItemSearchResult
Method | Note |
---|---|
String getErrorMessage() | Error message if there was a problem with the query. |
int getTotalRecordCount() | Total number of results for the search. |
int getPages() | Number of pages in the total result set. |
int getPage() | Current page number from the result set. |
AdvancedItemSearchResultRecord[] getPageRecords() | Records for this page. |
int getPageRecordCount() | Number of records per page. |
AdvancedItemSearchResultRecord
Method | Note |
---|---|
String getDescription() | Description of the item |
String getItemId() | Item ID of the item |
float getScore() | Score between 0 (lowest) - 1 (highest) of the result |
Item getItem() | Catalog item object of the item |
Sample Queries
In this section we'll look at how to build up some sample queries based a fictional user interface.
Let's break down the user interface and see what searches are have from a high level.
- The text field box needs to search across item id, description, extended description, manufacturer name, manufacturer SKU, and all attributes.
- The checkboxes for Color Group, Collection, Construction, and Content search various attributes that are on the item.
- The price range box filters items to certain price ranges.
Now let's look at what the Velocity looks like to build up the query.
## You will have to parse out the information from the $parameters map object. That is beyond the scope of this tutorial. #set ($selectedColorGroups = ["white", "black"]) #set ($selectedCollections = ["classic", "sheer"]) #set ($selectedConstructions = []) #set ($selectedContents = ["silk"]) #set ($selectedPrices = ["0-100", "101-200"]) #set ($searchTerm = "my search") ## ALWAYS GOOD TO RESET JUST TO BE SAFE $advancedItemSearchManager.resetManager() ## COLOR GROUP ATTRIBUTE #if ($selectedColorGroups.length > 0) $advancedItemSearchManager.and().resetModifiers().required(true).openGroup().noop() #foreach ($selectedColorGroup in $selectedColorGroups) $advancedItemSearchManager.attribute("colorGroup", $selectedColorGroup).noop() #end $advancedItemSearchManager.closeGroup().noop() #end ## COLLECTION ATTRIBUTE #if ($selectedCollections.length > 0) $advancedItemSearchManager.and().resetModifiers().required(true).openGroup().noop() #foreach ($selectedCollection in $selectedCollections) $advancedItemSearchManager.attribute("collection", $selectedCollection).noop() #end $advancedItemSearchManager.closeGroup().noop() #end ## CONSTRUCTION ATTRIBUTE #if ($selectedConstructions.length > 0) $advancedItemSearchManager.and().resetModifiers().required(true).openGroup().noop() #foreach ($selectedConstruction in $selectedConstructions) $advancedItemSearchManager.attribute("construction", $selectedConstruction).noop() #end $advancedItemSearchManager.closeGroup().noop() #end ## CONTENT ATTRIBUTE #if ($selectedContents.length > 0) $advancedItemSearchManager.and().resetModifiers().required(true).openGroup().noop() #foreach ($selectedContent in $selectedContents) $advancedItemSearchManager.attribute("content", $selectedContent).noop() #end $advancedItemSearchManager.closeGroup().noop() #end ## PRICE #if ($selectedPriceslength > 0) $advancedItemSearchManager.and().resetModifiers().required(true).openGroup().noop() #foreach ($selectedPrice in $selectedPrices) #if ($selectedPrice == "0-100") $advancedItemSearchManager.costBetween(0, 100).noop() #elseif ($selectedPrice == "101-200") $advancedItemSearchManager.costBetween(100.01, 200).noop() #elseif ($selectedPrice == "201-300") $advancedItemSearchManager.costBetween(200.01, 300).noop() #elseif ($selectedPrice == "301-400") $advancedItemSearchManager.costBetween(300.01, 400).noop() #elseif ($selectedPrice == "401-500") $advancedItemSearchManager.costBetween(400.01, 500).noop() #end #end $advancedItemSearchManager.closeGroup().noop() #end ## SEARCH FIELD #if ($searchTerm != "") $advancedItemSearchManager.and().resetModifiers().required(true).openGroup().noop() $advancedItemSearchManager.searchEachWord(true).noop() $advancedItemSearchManager.or().attributes($searchTerm).noop() $advancedItemSearchManager.or().barcode($searchTerm).noop() $advancedItemSearchManager.or().description($searchTerm).noop() $advancedItemSearchManager.or().extendedDescription($searchTerm).noop() $advancedItemSearchManager.or().itemId($searchTerm).noop() $advancedItemSearchManager.or().manufacturerName($searchTerm).noop() $advancedItemSearchManager.or().manufacturerSKU($searchTerm).noop() $advancedItemSearchManager.closeGroup().noop() #end
Now we need to execute the search and print out the results.
#set($results = $advancedItemSearchManager.search(1, 50)) <table> #foreach ($record in $results.getPageRecords()) <tr> <td>$record.getItemId()</td> <td>$record.getDescription()</td> <td>$record.getScore()</td> </tr> #end </table>
Other things to consider in your coding.
- Storing away the search parameters for the subsequent pages of the result set.
- Paging through results
- Check the error message in the result and displaying it.
Â
Â
Â
Â
Â
Â
Â
Â
Â
Â
Â
Â
Â
Â
Â