Coldfusion Solr Client - SolColdfusion

As I hinted at yesterday, I was close to having some code in the pipeline to abstract using Solr. I've finished the initial code with the following built in. Here's a brief setup guide to start playing with the code.

First, you're going to need to grab the latest release version of Solr (currently 1.2). The only real requirement to run this software is that you have a JRE of 1.5 or higher. Untar/zip the file somewhere convenient and open a command prompt. Get to the example directory in the apache-solr.1.2.x folder (cd /example). To start up the sample server running Jetty, just issue the following command:

java -jar start.jar

This will start a new instance of the Solr server on your computer on port 8983. You can make sure this is running by navigating to http://localhost:8983/solr (NOTE: this is a link to your computer. If you get an error, it's because your computer isn't running an instance of Solr on port 8983).

At this point, it's probably good to send you over to the Solr website to take a look at their tutorial. Go ahead. I'll wait...

...

Great, you're back.

You've seen some basic inserting, deleting, and querying of Solr index data. You may have also noticed that there are clients for PHP, Ruby, Python, and Java...no ColdFusion. I want to do a little more testing on this before I submit the patch, but I've added the initial code as an encosure here to do updating, deleting, and searching in Coldfusion.

The CFC SolColdfusion should be in the path org/apache/client (at least that's where I'm putting in for the purposes of this initial demonstration). The initialization takes one required parameter (the Solr host) and then has two optional parameters (port and path).

To set this up, create an instance with

<cfset solr = createObject("component", "org.apache.solr.client.SolColdfusion").init("http://localhost", "8983", "/solr") />

Now, there are a lot of different parameters you can send to Solr to perform different queries. And, since some of these key names can repeat, I chose to implement sending these parameters as an array. So, let's set this up.

<cfset params = arrayNew(1) />

<cfset params[1][1] = "indent">
<cfset params[1][2] = "on" />
<cfset params[2][1] = "wt">
<cfset params[2][2] = "standard" />
<cfset params[3][1] = "fl" />
<cfset params[3][2] = "*,score" />
<cfset params[4][1] = "qt" />
<cfset params[4][2] = "standard" />
<cfset params[5][1] = "wt" />
<cfset params[5][2] = "standard" />

These parameters are basically what are the defaults that Solr will return back to you. If you want highlighting, you would need to add two additional row vectors with 'hl = on' and 'hl.fl = '.

Searching is straight forward, taking a query, the start row, number of rows to return, and the array of parameters:

<cfset results = solr.search("*:*", 0, 10, params) />

This searches all fields and all content and returns back an XML document with the search results in it.

<cfdump var="#results#" />

In the result node, you'll see that Solr returns an xmlAttribute of

numFound
of 0 (assuming you don't have anything in the index). Let's add an example document from the documents that come with Solr.

<!--- Create a new sample document --->
<cfxml variable="sample">
<doc>
<field name="id">F8V7067-APL-KIT</field>
<field name="name">Belkin Mobile Power Cord for iPod w/ Dock</field>
<field name="manu">Belkin</field>
<field name="cat">electronics</field>
<field name="cat">connector</field>
<field name="features">car power adapter, white</field>
<field name="weight">4</field>
<field name="price">19.95</field>
<field name="popularity">1</field>
<field name="inStock">false</field>
</doc>
</cfxml>

<!--- add this document to the index --->
<cfset solr.add(sample) />
<cfset solr.commit() />
<cfset solr.optimize() />

<!--- search for the newly added document --->
<cfset results = solr.search("id:F8V7067-APL-KIT", 0, 10, params) />

<cfdump var="#xmlParse(results)#" />

You'll notice I used a commit and optmize statement. Neither of these statements are necessary every time you add a document, but be aware that Solr caches documents and won't flush the new documents to disk unless you either commit the documents or the mergefactor setting you used in your solrconfig.xml file has been reached.

Now, let's delete this document...

<cfset solr.deleteById("F8V7067-APL-KIT") />
<cfset solr.commit() />

Don't forget to commit deletions to the index!

There'll be more soon (add multiple documents, delete by queries). In the mean time, try it out. If you have any comments, questions, concerns, whatever, let me know.

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
Rob Brooks-Bilson's Gravatar Hi Wayne,

Thanks for this series. Good stuff and very timely (for me).
# Posted By Rob Brooks-Bilson | 10/4/07 4:55 PM
Rich Rein's Gravatar Very timely for us as well, as our current CF & Verity implementation reaches the upper limits of the bundled software. Unfortunately, the Java 1.5+ requirement looks like we are out of luck until we upgrade to CF8, so I will just be following along and playing with this for the time being...
# Posted By Rich Rein | 10/5/07 9:32 AM
Wayne Graham's Gravatar @richard

Solr pretty much needs its own server (or at least a J2EE container like Jetty, Tomcat, JBoss, ...) to run. You can also have multiple JVMs on the same server (just don't point your JVM in CF to the 1.5/6 version of the JDK). For most of my test boxes, I have an Apache server running CF on port 80, and a Jetty server running on 8983 (I used 8983 in case you're running JRun and using port 8080).

You know what, this actually should probably be another post...I'll get more on this up a bit later today.
# Posted By Wayne Graham | 10/5/07 9:42 AM
Sven Delporte's Gravatar Thank you for this component.

I tried it out on a tomcat, but the i can't search anything. Adding documents to the index and deleting them works fine but every time i try to search for something i get this cfm error.
" The argument PARAMS passed to function search() is not of type struct."

I think my setup works fine because i can access the solr admin and i can run a cfdump of my component.

Anybody has an idea what i'm missing here? Thanks in advance
# Posted By Sven Delporte | 1/3/08 4:06 AM
Wayne Graham's Gravatar Are you passing a "struct" into the search method? I'm going to be doing some more work with this next week...might take out the required parameter struct then.
# Posted By Wayne Graham | 1/3/08 8:59 AM
Sven Delporte's Gravatar I used the example above.
i created an array of params end sent that to the search
# Posted By Sven Delporte | 1/16/08 9:08 AM
Paul Treszczotko's Gravatar Great stuff Wayne! Let me know if you need help with this project!

Sven try this, this should do the trick:

<!--- init --->
<cfset solr1 = createObject("component", "org.apache.solr.client.SolColdfusion").init("http://localhost", "8983", "/solr") />
<!--- create a struct to hold search params and the query - last item in the struct --->
<cfset params= structNew()>
<cfset params.indent="on">
<cfset params.wt="standard">
<cfset params.fl="*,score">
<cfset params.qt="standard">
<cfset params.wt="standard">
<!--- this is the query attrbt --->
<cfset params.q="a">
<!--- call the search method --->
<cfset results = solr1.search(params) />
<!--- dump xml --->
<cfdump var="#results#" />
# Posted By Paul Treszczotko | 1/17/08 7:49 PM
ilcy's Gravatar wayne,

does SOLcoldfusion search binary files like PDFs?
# Posted By ilcy | 2/14/08 7:42 PM
ilcy's Gravatar Wayne,

I'd like to know if the coldfusion client can search binary files like PDFs?
Thanks!
# Posted By ilcy | 2/14/08 7:54 PM