Earlier this week a reader came to me with an interesting question. They were using Solr and ColdFusion 9 and had a collection of products they wanted searched. That part wasn't difficult. But here comes the interesting part. His products were split between male and female products (imagine clothing) as well as unisex items. A search for male products should return both male and unisex items while a search for female products would return female and unisex. This ended up being pretty easy to do and I thought I'd share the example code I wrote.
I'll begin by sharing the test script I wrote to setup the collection and index. This handles the initial collection creation and then populates the index with fake data. Obviously I could have made this data bit more interesting but hopefully you can see that I've got some male, some female, and some unisex products.
<cfif not listFindNoCase(valueList(collections.name),collection)>
<cfcollection action="create" collection="#collection#" path="#server.coldfusion.rootdir#\collections" engine="solr" categories="true">
<cfoutput>
Making collection.
<p/>
</cfoutput>
</cfif> <cfset products = queryNew("id,title,body,gender","integer,varchar,varchar,varchar")>
<cfset queryAddRow(products)>
<cfset querySetCell(products, "id", 1)>
<cfset querySetCell(products, "title", "Boy One")>
<cfset querySetCell(products, "body", "Body One")>
<cfset querySetCell(products, "gender", "male")>
<cfset queryAddRow(products)>
<cfset querySetCell(products, "id", 2)>
<cfset querySetCell(products, "title", "Boy Two")>
<cfset querySetCell(products, "body", "Body Two")>
<cfset querySetCell(products, "gender", "male")>
<cfset queryAddRow(products)>
<cfset querySetCell(products, "id", 3)>
<cfset querySetCell(products, "title", "Boy Three")>
<cfset querySetCell(products, "body", "Body Three")>
<cfset querySetCell(products, "gender", "male")>
<cfset queryAddRow(products)>
<cfset querySetCell(products, "id", 4)>
<cfset querySetCell(products, "title", "Girl One")>
<cfset querySetCell(products, "body", "Body One")>
<cfset querySetCell(products, "gender", "female")>
<cfset queryAddRow(products)>
<cfset querySetCell(products, "id", 5)>
<cfset querySetCell(products, "title", "Girl Two")>
<cfset querySetCell(products, "body", "Body Two")>
<cfset querySetCell(products, "gender", "female")>
<cfset queryAddRow(products)>
<cfset querySetCell(products, "id", 6)>
<cfset querySetCell(products, "title", "Girl Three")>
<cfset querySetCell(products, "body", "Body Three")>
<cfset querySetCell(products, "gender", "female")>
<cfset queryAddRow(products)>
<cfset querySetCell(products, "id", 7)>
<cfset querySetCell(products, "title", "Girl Four")>
<cfset querySetCell(products, "body", "Body Four")>
<cfset querySetCell(products, "gender", "female")>
<cfset queryAddRow(products)>
<cfset querySetCell(products, "id", 8)>
<cfset querySetCell(products, "title", "Girl Five")>
<cfset querySetCell(products, "body", "Body Five")>
<cfset querySetCell(products, "gender", "female")>
<cfset queryAddRow(products)>
<cfset querySetCell(products, "id", 9)>
<cfset querySetCell(products, "title", "Unisex One")>
<cfset querySetCell(products, "body", "Body One")>
<cfset querySetCell(products, "gender", "unisex")>
<cfset queryAddRow(products)>
<cfset querySetCell(products, "id", 10)>
<cfset querySetCell(products, "title", "Unisex Two")>
<cfset querySetCell(products, "body", "Body Two")>
<cfset querySetCell(products, "gender", "unisex")> <cfindex action="refresh" collection="#collection#" query="products" key="id" title="title" body="body" category="gender" status="s">
<cfdump var="#s#">
<cfset collection = "productgender">
<cfcollection action="list" engine="solr" name="collections">
Very exciting, right? Well let's look at the search interface where things do get a bit interesting.
<cfoutput>
<form action="test.cfm" method="post">
Keyword:<br/>
<input type="test" name="search" value="#form.search#"><br/>
Gender:<br/>
<select name="gender">
<option value="" <cfif form.gender is "">selected</cfif>>--</option>
<option value="male" <cfif form.gender is "male">selected</cfif>>For Him</option>
<option value="female" <cfif form.gender is "female">selected</cfif>>For Her</option>
</select><br/>
<input type="submit" value="Search">
</form>
</cfoutput> <cfif len(form.search) or form.gender neq ""> <cfset category = "">
<cfif form.gender is "male">
<cfset category = "male,unisex">
<cfelseif form.gender is "female">
<cfset category = "female,unisex">
</cfif> <cfsearch collection="productgender" criteria="#trim(form.search)#" category="#category#" name="results">
<cfdump var="#results#"> </cfif>
<cfparam name="form.search" default="">
<cfparam name="form.gender" default="">
I begin by creating a simple form that allows for both free text entry and selecting "For Him" or "For Her" products. The whole "For" thing was just me being fancy. Below the form is the real interesting part. If a search was made (and we allow you to pick a gender and leave the text field blank) we create a category field based on the gender. We simply append unisex to the selected value and pass this as the category field in the cfsearch tag. You can play with this yourself here: