Chapter 18

Online Store Product Searches


CONTENTS

If you start to sell a large quantity of items through your online store, it may take some time for users to poke through your catalog to find just what they want. In cases like this, having some way to search your selections is in order.

Using Product Keys

Chapter 16, "Searching the Database," introduces the concepts of search keys to make it easier to find information in a database. To review, a key is a field within the database used as match criterion to locate a particular record; in this case, an item from the catalog.

Keys can work in two different ways: searching and sorting. Because each product in the catalog has a unique number (the order code) associated with it, that field would best be used for sorting, with the other fields being used to search, as customers will remember "Parka" more often than "PK4256."

Within database jargon, the field on which you base your search is referred to as a search key. Keys aren't limited to just a single field-you could create a complex key that consists of more than one field, such as state and last name, which is especially valuable when several database records may have the same information in one or more fields. Nor are keys limited to using the entire field, such as when you wish to find all entries in a database that start with "W."

Alternatively, you could create a totally new field for tracking purposes in which to store a custom key.

Regardless of how you construct your keys, you'll need to utilize a relatively fast search algorithm, especially as your online catalog grows. A good quick algorithm is the binary search from chapter 16, "Searching the Database," which splits the database in half again and again looking for a matching key. Listing 18.1 takes a fresh look at the binary search, and introduces some new tricks as well.


Listing 18.1  Locating a Record with a Binary Search
sub BinarySearch {
   local ($key, *catalog) = @_;
   local ($howMany, $first, $last);
   $howMany = @catalog;
   $first   = 0;
   $last    = $howMany - 1;

   while(true) {
      $index  = $first + ($last - $first) / 2;
      $testKey = split(/\|/, $keyField[$index], 2);
 
      if($testKey =~ /$key/) {
         break;
      }

      if($testKey < $key) {
         # record comes before key
         $first = $index + 1;
      } elsif ($testKey > $key) {
         # record comes after key
         $last = $index - 1;
      } else {
         # at this point, we've no match
         $index = $howMany;
      }
   }

   if ($index < $howMany) {
      return $keyField[$index];
   } else {
      return null;
   }
}

This function takes two parameters, the first being the key to search for, the second being the array to search. It returns the matching record found, or null if no match was found. For example:

$result = &BinarySearch("P1512", *catalog);

would search the @catalog array for a product whose code is P1512.

NOTE
You'll note in the previous function call that the array, normally prefaced by an ampersand (@) was prefaced by an asterisk (*) when passed as a parameter. This is how you pass arrays (or any variable, for that matter) by reference from within Perl.

Allowing for Partial Matches

More than likely, your users will be looking for "something like" or "something that has the word 'modem' in it" rather than searching for a specific instance. In that case, the search engine should be designed to return more than one possible answer, giving the user the opportunity to pick from the results. Figure 18.1 is an example of such a catalog search, taken from the home site of Egghead Discount Software (http://www.egghead.com/).

Figure 18.1 : An example page returned from a catalog search at the Egghead Discount Software site. Depending on the types of products you choose to sell, the data columns your search will display can vary greatly.

Implementing a multiple-response search is a straightforward process of pulling a sublist out of the master database list. Listing 18.2 demonstrates a code fragment that performs such a search, building a mini-database of matching records in the list $results[].


Listing 18.2  Retrieving Multiple Records
# listDB contains the database records
# key is the desired key to match
#
$numItems = @listDB;
for ($index = 0; $index < $numItems; $index++) {
   if ($listDB[$index] =~ /$key/) {
      push (@results, $listDB[$index]);
   }
}

if (@results) {
   # found some matches
} else {
   # no matches found
}

If you remember from chapter 16, "Searching the Database," this is based on the brute-force search algorithm. Because you're looking for all references to $key within the database, starting at the beginning and working your way to the end is a practical method.

A side benefit of this trick is gained if you maintain the database as a record list, with each entry containing all the fields of the record, instead of cracking the individual records into field elements. If the entire record is contained within a list entry, the value in $key is checked against the entire record, which includes all fields. If your database has several long fields, such as a product title, product description, and product color, this method checks everywhere for a possible match.

Displaying the Search Results

Once the $results[] list has been created, displaying it back to the user is done by creating a simple table, as shown in listing 18.3.


Listing 18.3  Generating a Result Table
print "Content-type: text/html\n\n";

print "<TABLE BORDER=3>\n";
foreach $record (@results) {
   &PrintLink ($record);
}
print "</TABLE>";

The Perl foreach statement steps through the results list one record at a time, passing the returned record off to the PrintLink function. PrintLink (listing 18.4) is the real workhorse, in that it generates the HTML table record, creating the necessary hyperlink.


Listing 18.4  Creating a Product Link
sub PrintLink {
   local ($code, $desc, $price);

   # crack the record
   ($code, $desc, $price) = split (/\|/, $_[0]);

   # Build the entry
   print "<TR>\n";
   print "<TD>$code</TD>\n";
   print "<TD><A HREF=\"$code.html\">$desc</TD>\n";
   print "<TD>$price</TD>\n";
   print "<TD><A HREF="\"/cgi-bin/order?$code\">Purchase</A></TD>\n";
   print "</TR>\n";
}

The last table element is a line to the order processing script (the shopping cart), passing the product code to the cart for storage. This makes it easy for customers to purchase a product no matter where they are in your store. Remember a fundamental rule of sales: "Always ask for the sale." If you don't give a browser an opportunity to buy-he or she won't.

From Here…

In this chapter, you extended the functionality of your online catalog to include searching the database for items. For more information on ways to use these tricks, check out: