Not sure if anyone will find this helpful, but here goes. A user reported some dissatisfaction with the search engine at CFLib. Specifically a search for FOO GOO would result in an exact phrase match on foo goo. It would not match a UDF named MyFooMilkshakeBetterThanGoo.
This was because my search did the rather simple %SEARCH% style match (ie, match the search term exactly, case insensntive). Here is the original Transfer code I used for the search:
1 <cfsavecontent variable="sql">
2 from udf.udf
3 where (udf.udf.name like :search
4 or udf.udf.shortdescription like :search
5 or udf.udf.description like :search)
6 and udf.udf.released = :active
7 order by udf.udf.name asc
8 </cfsavecontent>
9
10 <cfset q = variables.transfer.createQuery(sql)>
11 <cfset q.setParam("search", "%" & arguments.search & "%", "string")>
12 <cfset q.setParam("active", true, "boolean")>
13 <cfset q.setCacheEvaluation(true)>
Even if you don't know Transfer, this should be readable to you. I do a match on either name, shortdescription, or description. If you search for FOO, then basically it ends up being a search on %FOO%. Again though this kind of breaks down when you search for multiple words.
I wanted to keep things simple, so I decided that any multiword search would be an AND style search (ie, all the words must match), and I'd split on an empty space. I rewrote the TQL like so:
2 from udf.udf
3 where (udf.udf.name like :search
4 or udf.udf.shortdescription like :search
5 or udf.udf.description like :search)
6 and udf.udf.released = :active
7 order by udf.udf.name asc
8 </cfsavecontent>
9
10 <cfset q = variables.transfer.createQuery(sql)>
11 <cfset q.setParam("search", "%" & arguments.search & "%", "string")>
12 <cfset q.setParam("active", true, "boolean")>
13 <cfset q.setCacheEvaluation(true)>
1 <cfsavecontent variable="sql">
2 from udf.udf
3 where (
4 <cfloop index="idx" from="1" to="#arrayLen(words)#">
5 <cfoutput>
6 (udf.udf.name like :word#idx#
7 or udf.udf.shortdescription like :word#idx#
8 or udf.udf.description like :word#idx#
9 ) <cfif idx lt arrayLen(words)>and</cfif>
10 </cfoutput>
11 </cfloop>
12 )
13 and udf.udf.released = :active
14 order by udf.udf.name asc
15 </cfsavecontent>
16
17 <cfset q = variables.transfer.createQuery(sql)>
18 <cfloop index="idx" from="1" to="#arrayLen(words)#">
19 <cfset q.setParam("word#idx#", "%" & words[idx] & "%", "string")>
20 </cfloop>
21 <cfset q.setParam("active", true, "boolean")>
22 <cfset q.setCacheEvaluation(true)>
First off, the variables words comes from this change in the function header:
2 from udf.udf
3 where (
4 <cfloop index="idx" from="1" to="#arrayLen(words)#">
5 <cfoutput>
6 (udf.udf.name like :word#idx#
7 or udf.udf.shortdescription like :word#idx#
8 or udf.udf.description like :word#idx#
9 ) <cfif idx lt arrayLen(words)>and</cfif>
10 </cfoutput>
11 </cfloop>
12 )
13 and udf.udf.released = :active
14 order by udf.udf.name asc
15 </cfsavecontent>
16
17 <cfset q = variables.transfer.createQuery(sql)>
18 <cfloop index="idx" from="1" to="#arrayLen(words)#">
19 <cfset q.setParam("word#idx#", "%" & words[idx] & "%", "string")>
20 </cfloop>
21 <cfset q.setParam("active", true, "boolean")>
22 <cfset q.setCacheEvaluation(true)>
1 <cfset var words = listToArray(arguments.search," ")>
So a search for FOO GOO results in words being equal to ["FOO","GOO"]. Notice then my loop over the array. I didn't use the new array style cfloop as I wanted a counter variable I could check to see if I needed an AND at the end of each block.
The next change was to have a dynamic set of setParams. This will replace word1, word2, etc, with the proper value from the array.
A good test for this is a search for "host url". Before the change it returned nothing. Now it matches getCurrentURL, getHostFromURL, and getHostFromURLJava.
Comment 1 written by Timothy Farrar on 23 September 2008, at 9:12 AM
Any chance of adding this type of functionality to the search on riaForge?
Comment 2 written by Raymond Camden on 23 September 2008, at 9:15 AM
Comment 3 written by Timothy Farrar on 23 September 2008, at 9:18 AM
Comment 4 written by Raymond Camden on 23 September 2008, at 9:21 AM
Comment 5 written by Nathan D on 23 September 2008, at 9:50 AM
Comment 6 written by Raymond Camden on 23 September 2008, at 9:59 AM
Comment 7 written by Aegis on 23 September 2008, at 9:46 PM
[Add Comment] [Subscribe to Comments]