Skip to content

Commit 2116491

Browse files
committed
Added faceted search capabilities with an example page.
1 parent 483d01a commit 2116491

File tree

4 files changed

+189
-3
lines changed

4 files changed

+189
-3
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@
44

55
.DS_Store
66
solr-server/solr/data/index
7+
solr-server/solr/collection1/data/tlog/

components/cfsolrlib.cfc

+18
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,9 @@
110110
<cfargument name="rows" type="numeric" required="false" default="20" hint="Number of rows you want returned" />
111111
<cfargument name="highlightingField" type="string" required="false" hint="Name of the field used for the highlighting result" />
112112
<cfargument name="params" type="struct" required="false" default="#structNew()#" hint="A struct of data to add as params. The struct key will be used as the param name, and the value as the param's value. If you need to pass in multiple values, make the value an array of values." />
113+
<cfargument name="facetFields" type="array" required="false" default="#arrayNew(1)#" hint="An array of fields to facet." />
114+
<cfargument name="facetMinCount" type="numeric" required="false" default="1" hint="Minimum number of results to return a facet." />
115+
<cfargument name="facetFilters" type="array" required="false" default="#arrayNew(1)#" hint="An array of facet filters." />
113116
<cfset var thisQuery = THIS.javaLoaderInstance.create("org.apache.solr.client.solrj.SolrQuery").init(ARGUMENTS.q).setStart(ARGUMENTS.start).setRows(ARGUMENTS.rows) />
114117
<cfset var thisParam = "" />
115118
<cfset var response = "" />
@@ -119,6 +122,16 @@
119122
<cfset var suggestions = "" />
120123
<cfset var thisSuggestion = "" />
121124
<cfset var iSuggestion = "" />
125+
126+
<cfif NOT arrayIsEmpty(ARGUMENTS.facetFields)>
127+
<cfset thisQuery.setFacet(true)>
128+
<cfset thisQuery.addFacetField(javaCast("string[]",facetFields))>
129+
<cfset thisQuery.setFacetMinCount(ARGUMENTS.facetMinCount)>
130+
</cfif>
131+
132+
<cfif NOT arrayIsEmpty(ARGUMENTS.facetFilters)>
133+
<cfset thisQuery.addFilterQuery(javaCast("string[]",ARGUMENTS.facetFilters))>
134+
</cfif>
122135

123136
<cfloop list="#structKeyList(ARGUMENTS.params)#" index="thisKey">
124137
<cfif isArray(ARGUMENTS.params[thisKey])>
@@ -162,6 +175,11 @@
162175
<cfset currentResult.highlightingResult = response.getHighlighting().get("#currentResult.get('id')#").get("#ARGUMENTS.highlightingField#") />
163176
</cfloop>
164177
</cfif>
178+
179+
<cfif NOT isNull(response.getFacetFields())>
180+
<cfset ret.facetFields = arrayNew(1)>
181+
<cfset ret.facetFields = response.getFacetFields()>
182+
</cfif>
165183
<cfreturn duplicate(ret) /> <!--- duplicate clears out the case-sensitive structure --->
166184
</cffunction>
167185

facetExample.cfm

+162
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
<cfparam name="URL.q" default="*:*">
2+
<cfparam name="URL.page" default="1">
3+
<cfparam name="URL.perPage" default="10">
4+
5+
<cfset sampleSolrInstance = createObject("component","components.cfsolrlib").init(APPLICATION.javaloader,"localhost","8983","/solr") />
6+
7+
<cfif NOT isNumeric(URL.page) OR abs(round(URL.page)) NEQ URL.page>
8+
<cfset URL.page = 1>
9+
</cfif>
10+
11+
<cfif NOT isNumeric(URL.perPage) OR abs(round(URL.perPage)) NEQ URL.perPage>
12+
<cfset URL.perPage = 10>
13+
</cfif>
14+
15+
<cfset start = ((URL.page - 1) * URL.perPage)>
16+
<cfset rows = URL.perPage>
17+
18+
<cfset cleanedUrlQuery = "?" & reReplaceNoCase(cgi.query_string,"&*\bpage=\d+","","all")>
19+
20+
<cfset facetFields = arrayNew(1) />
21+
<cfset arrayAppend(facetFields,"cat") />
22+
<cfset arrayAppend(facetFields,"author_s") />
23+
<cfset arrayAppend(facetFields,"availability_s") />
24+
25+
<cfset facetFiltersArray = arrayNew(1)>
26+
27+
<cfif isDefined("URL.fq")>
28+
<cfset facetFiltersArray = listToArray(urlDecode(URL.fq))>
29+
</cfif>
30+
31+
<cfset searchResponse = sampleSolrInstance.search(q=URL.q,start=start,rows=rows,facetFields=facetFields,facetFilters=facetFiltersArray,facetMinCount=1) />
32+
33+
<cfif isStruct(searchResponse)>
34+
<cfset searchSuccess = TRUE>
35+
<cfelse>
36+
<cfset searchSuccess = FALSE>
37+
</cfif>
38+
39+
<!doctype html>
40+
<html lang="en">
41+
<head>
42+
<meta charset="UTF-8">
43+
<title>CFSolrLib 3.0 | Faceted Search Example</title>
44+
<link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.0/css/bootstrap-combined.min.css" rel="stylesheet">
45+
</head>
46+
<body>
47+
<cfoutput>
48+
<div class="container">
49+
<div class="row">
50+
<div class="span12">
51+
<h1>Faceted Search Example</h1>
52+
<p class="lead">Here is a simple faceted search example.</p>
53+
<form action="" method="GET" class="form-search form-inline">
54+
<div class="input-append">
55+
<input type="text" name="q" value="#URL.q#" class="input-medium search-query" placeholder="Search..."><button type="submit" class="btn">Search</button>
56+
</div>
57+
</form>
58+
<p>Other Search Examples: <a href="?q=*:*">*:*</a> | <a href="?q=Charcoal">Charcoal</a> | <a href="?q=Media">Media</a></p>
59+
</div>
60+
</div>
61+
<div class="row">
62+
<div class="span3">
63+
<cfif searchSuccess AND structKeyExists(searchResponse,"facetFields") AND isArray(searchResponse.facetFields)>
64+
<cfoutput>
65+
<cfset facetDisplayName = structNew()>
66+
<cfset facetDisplayName["cat"] = "Media">
67+
<cfset facetDisplayName["Author_s"] = "Artist">
68+
<cfset facetDisplayName["Availability_s"] = "Availability">
69+
<cfloop index="a" array="#searchResponse.facetFields#">
70+
<cfif isArray(a.getValues())>
71+
<h4 style="text-transform:capitalize;">#facetDisplayName[a.getName()]#</h4>
72+
<ul>
73+
<cfloop index="b" from="1" to="#arrayLen(a.getValues())#">
74+
<cfif len(a.getValues()[b].getName())>
75+
<cfset filterString = "&fq=" & a.getName() & urlEncodedFormat(":("""& a.getValues()[b].getName()&""")")>
76+
<li><a href="#cleanedUrlQuery##filterString#">#a.getValues()[b].getName()#</a>&nbsp;<small class="muted">(#a.getValues()[b].getCount()#)</small>
77+
<cfif isDefined("URL.fq") and findNoCase(filterString,cleanedUrlQuery)> <a href="#replaceNoCase(cleanedUrlQuery,filterString,"")#" class="label label-important" style="float:none;">&times;</a>
78+
</cfif>
79+
</li>
80+
</cfif>
81+
</cfloop>
82+
</ul>
83+
</cfif>
84+
</cfloop>
85+
</cfoutput>
86+
&nbsp;
87+
</cfif>
88+
</div>
89+
<div class="span9">
90+
<cfif searchSuccess AND isArray(searchResponse.results)>
91+
<table class="table table-bordered table-hover">
92+
<thead>
93+
<tr>
94+
<th>ID</th>
95+
<th>Title</th>
96+
<th>Artist</th>
97+
<th>Media</th>
98+
<th>Availability</th>
99+
</tr>
100+
</thead>
101+
<tbody>
102+
<cfloop array="#searchResponse.results#" index="currentResult">
103+
<tr>
104+
<td>#currentResult.id#</td>
105+
<td><cfif isDefined("currentResult.title")>#currentResult.title#</cfif></td>
106+
<td><cfif isDefined("currentResult.Author_s")>#currentResult.Author_s#</cfif></td>
107+
<td><cfif isDefined("currentResult.cat")>#arrayToList(currentResult.cat)#</cfif></td>
108+
<td><cfif isDefined("currentResult.Availability_s")>#currentResult.Availability_s#</cfif></td>
109+
</tr>
110+
</cfloop>
111+
</tbody>
112+
</table>
113+
114+
115+
<!--- Begin Pagination --->
116+
<cfif searchResponse.totalResults GT rows>
117+
<div class="pagination">
118+
<ul>
119+
<cfoutput>
120+
<cfset totalPages = Ceiling(searchResponse.totalResults / url.perPage)>
121+
<cfif url.page GT 1>
122+
<cfset prevLink = cleanedUrlQuery>
123+
<cfif url.page GT 2>
124+
<cfset prevLink = cleanedUrlQuery & "&page=" & (url.page - 1)>
125+
</cfif>
126+
<li><a href="#prevLink#">&laquo;</a></li>
127+
<cfelse>
128+
<li class="disabled"><a href="##">&laquo;</a></li>
129+
</cfif>
130+
131+
<cfset pageCount = 1>
132+
<cfset pageLink = 1>
133+
134+
<cfloop index="c" from="1" to="#totalPages#">
135+
<cfif c EQ url.page>
136+
<li class="active"><a href="##">#c#</a></li>
137+
<cfelseif c NEQ 1>
138+
<li><a href="#cleanedUrlQuery#&page=#c#">#c#</a></li>
139+
<cfelse>
140+
<li><a href="#cleanedUrlQuery#">#c#</a></li>
141+
</cfif>
142+
</cfloop>
143+
144+
<cfif url.page LT totalPages>
145+
<cfset nextLink = cleanedUrlQuery & "&page=" & (url.page + 1)>
146+
<li><a href="#nextLink#">&raquo;</a></li>
147+
<cfelse>
148+
<li class="disabled"><a href="##">&raquo;</a></li>
149+
</cfif>
150+
</cfoutput>
151+
</ul>
152+
</div>
153+
</cfif>
154+
<!--- End Pagination --->
155+
156+
</cfif>
157+
</div>
158+
</div>
159+
</div>
160+
</cfoutput>
161+
</body>
162+
</html>

indexExample.cfm

+8-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
<cfset sampleSolrInstance = createObject("component","components.cfsolrlib").init(APPLICATION.javaloader,"localhost","8983","/solr") />
22

33
<cfquery name="getArt" datasource="cfartgallery">
4-
SELECT artID, artname, description
5-
FROM art
4+
SELECT artID, artname, description, firstName, lastName, isSold
5+
FROM art
6+
LEFT JOIN artists
7+
ON art.artistId = artists.artistId
68
</cfquery>
79

810
<cfscript>
@@ -11,7 +13,10 @@ FROM art
1113
thisDoc = arrayNew(1);
1214
thisDoc = sampleSolrInstance.addField(thisDoc,"id",getArt.artID[i]);
1315
thisDoc = sampleSolrInstance.addField(thisDoc,"title",getArt.artname[i]);
14-
thisDoc = sampleSolrInstance.addField(thisDoc,"description",getArt.description[i]);
16+
thisDoc = sampleSolrInstance.addField(thisDoc,"cat",trim(getArt.description[i]));
17+
thisFullname = trim(getArt.firstName[i]&" "&getArt.lastName[i]);
18+
thisDoc = sampleSolrInstance.addField(thisDoc,"author",thisFullname);
19+
thisDoc = sampleSolrInstance.addField(thisDoc,"availability_s",iif(getArt.isSold[i] EQ 1,DE("Sold"),DE("Available")));
1520
sampleSolrInstance.add(thisDoc);
1621
}
1722

0 commit comments

Comments
 (0)