A robust starter web application to ease Java webapp development.

Home | Tutorials | Demos | Issues

 « Return to Thread: search - integrate compass (lucene) and appfuse

search - integrate compass (lucene) and appfuse

by Chris Barham :: Rate this Message:

Reply to Author | View in Thread

Hi,

I've been playing with Compass and Appfuse to give search capability.
I made notes as I was going and post them here in case anyone else
finds them useful.  A big thanks to Matt and Shay for these two
projects, they work so well together :-)

This is a barebones setup, my next job, (I think), is to rework the
SpringController to give back a list with highlight terms on the
search results so that Displaytag can render it, (If anyone has done
this please let me know if this is the best approach).

Once running you can browse the index using Luke http://www.getopt.org/luke/

Steps as follows:

Integrate Compass search with Appfuse
-----------------------------------------------------

1. Get a new latest Appfuse project setup a la
http://raibledesigns.com/wiki/AppFuseQuickStart.html  For this I used
a project called weblogs, using Spring MVC and hibernate (Apache Derby
as the RDBMS)
2. Get Spring 2.0 (currently Rc1) http://www.springframework.org/download
3. Get Compass (currently 0.9.2SNAPSHOT) http://www.opensymphony.com/compass/
4. Install these…
a. Make directories under lib directory place jars as follows:

compass-0.9.2-SNAPSHOT
|-- commons-logging.jar
|-- compass.jar
|-- lucene-analyzers.jar
|-- lucene-core.jar
|-- lucene-highlighter.jar
`-- lucene-snowball.jar

and

spring-2.0RC1/
|-- acegi-security-1.0.0-RC2.jar
|-- commons-codec-1.3.jar
|-- ehcache-1.2.jar
|-- spring-aspects.jar
|-- spring-mock.jar
|-- spring.jar
|-- springmodules-validator-dev-20051217.jar
`-- validator-rules.xml


b. Change lib.properties:

#
# Spring Framework - http://www.springframework.org
#
spring.version=2.0RC1
spring.dir=${lib.dir}/spring-${spring.version}
spring.jar=${spring.dir}/spring.jar

#
# Compass search http://www.opensymphony.com/compass/
#
compass.version=0.9.2-SNAPSHOT
compass.dir=${lib.dir}/compass-${compass.version}

5. Add compass to the service.compile.classpath and
web.compile.classpath in properties.xml:
        <fileset dir="${compass.dir}" includes="*.jar" />
6. Add the compass jars to the war task in build.xml (so they get
copied into the war)
         <lib dir="${compass.dir}" includes="*.jar"/>
7. Add the metadata files to src/dao/../model/
Weblogs.cmd.xml – common metadata (optional) - this doesn't get used
in this example
E.g.:
<?xml version="1.0"?>
<!DOCTYPE compass-core-meta-data PUBLIC
    "-//Compass/Compass Core Meta Data DTD 1.0//EN"
    "http://www.opensymphony.com/compass/dtd/compass-core-meta-data.dtd">

<compass-core-meta-data>
        <meta-data-group id="weblogs" displayName="Weblogs Meta Data">
                <description>mongoose Meta Data</description>
                 <uri>http://compass/weblogs</uri>
                <meta-data id="createddate" displayName="createddate">
                        <description>CreatedDate</description>
                        <uri>http://compass/weblogs/createddate</uri>
                        <name format="dd/MM/yyyy">createddate</name>
                </meta-data>
        </meta-data-group>
</compass-core-meta-data>


Mapping metadata: weblogs.cpm.xml

<?xml version="1.0"?>
<!DOCTYPE compass-core-mapping PUBLIC
    "-//Compass/Compass Core Mapping DTD 1.0//EN"
    "http://www.opensymphony.com/compass/dtd/compass-core-mapping.dtd">

<compass-core-mapping package="com.pobox.cbarham.model">
        <!-- ============================================= -->
        <!--  USER           -->
        <!-- ============================================= -->
        <class name="User" alias="user" root="true">
                <id name="id" />
                <constant>
                        <meta-data>type</meta-data>
                        <meta-data-value>user</meta-data-value>
                </constant>
                <property name="lastName">
                        <meta-data boost="2">lastName</meta-data>
                </property>
                <property name="firstName">
                        <meta-data>firstName</meta-data>
                </property>
                <property name="enabled">
                        <meta-data>enabled</meta-data>
                </property>
                <property name="phoneNumber">
                        <meta-data>phoneNumber</meta-data>
                </property>
                <property name="email">
                        <meta-data>email</meta-data>
                </property>
                <property name="address">
                        <meta-data>address</meta-data>
                </property>
                <property name="email">
                        <meta-data>email</meta-data>
                </property>
                <property name="accountExpired">
                        <meta-data>accountExpired</meta-data>
                </property>
                <property name="accountLocked">
                        <meta-data>accountLocked</meta-data>
                </property>
                <property name="username">
                        <meta-data>username</meta-data>
                </property>
                <property name="website">
                        <meta-data>website</meta-data>
                </property>

                <component name="roles" ref-alias="role" />
                <component name="address" ref-alias="address" />
        </class>
        <!-- ============================================= -->
        <!--  ROLE            -->
        <!-- ============================================= -->
        <class name="Role" alias="role" root="false">
                <id name="id" />
                <constant>
                        <meta-data>type</meta-data>
                        <meta-data-value>role</meta-data-value>
                </constant>
                <property name="description">
                        <meta-data>description</meta-data>
                </property>
                <property name="name">
                        <meta-data>name</meta-data>
                </property>
        </class>
        <!-- ============================================= -->
        <!--  ADDRESS            -->
        <!-- ============================================= -->
        <class name="Address" alias="address" root="false">
                <constant>
                        <meta-data>type</meta-data>
                        <meta-data-value>address</meta-data-value>
                </constant>
                <property name="address">
                        <meta-data>address</meta-data>
                </property>
                <property name="city">
                        <meta-data>address</meta-data>
                </property>
                <property name="country">
                        <meta-data>address</meta-data>
                </property>
                <property name="postalCode">
                        <meta-data>address</meta-data>
                </property>
                <property name="province">
                        <meta-data>address</meta-data>
                </property>
        </class>

</compass-core-mapping>

8. Edit src/service/…/service/applicationContext-service.xml
 And add the compass spring beans: (change the resource locations
accordingly) – also note that this puts the index on the root
filesystem in a directory called compass

        <!-- COMPASS START -->
        <bean id="compass" class="org.compass.spring.LocalCompassBean">
                <property name="resourceLocations">
                        <list>
                                <value>classpath:{PATH-TO-MODEL} /model/weblogs.cmd.xml</value>
                                <value>classpath: :{PATH-TO-MODEL /model/weblogs.cpm.xml</value>
                        </list>
                </property>
                <property name="compassSettings">
                        <props>
                                <prop key="compass.engine.connection">file:///compass/weblogs</prop>
                                <prop key="compass.transaction.factory">org.compass.spring.transaction.SpringSyncTransactionFactory</prop>
                        </props>
                </property>
                <property name="transactionManager" ref="transactionManager" />
        </bean>
        <bean id="hibernateGpsDevice"
class="org.compass.spring.device.hibernate.SpringHibernate3GpsDevice">
                <property name="name">
                        <value>hibernateDevice</value>
                </property>
                <property name="sessionFactory" ref="sessionFactory" />

        </bean>
        <bean id="compassGps" class="org.compass.gps.impl.SingleCompassGps"
init-method="start" destroy-method="stop">
                <property name="compass">
                        <ref bean="compass" />
                </property>
                <property name="gpsDevices">
                        <list>
                                <bean class="org.compass.spring.device.SpringSyncTransactionGpsDeviceWrapper">
                                        <property name="gpsDevice" ref="hibernateGpsDevice" />
                                </bean>
                        </list>
                </property>
        </bean>
        <!-- COMPASS END -->

9. Add in the JSP's to drive the index and search….
a. Under web/pages add a reindex.jsp:
<%@ include file="/common/taglibs.jsp"%>
<P>
<H2>Compass Index</H2>
<P>
Use the Index button to index the database using Compass::Gps. The
operation will
delete the current index and reindex the database based on the
mappings and devices
defined in the Compass::Gps configuration context.
<FORM method="POST" action="<c:url value="/reindex.html"/>">
        <spring:bind path="command.doIndex">
                <INPUT type="hidden" name="doIndex" value="true" />
        </spring:bind>
    <INPUT type="submit" value="Index"/>
</FORM>
<c:if test="${! empty indexResults}">
        <P>Indexing took: <c:out value="${indexResults.indexTime}" />ms.
</c:if>
<P>

b. under web/pages add search.jsp:
<%@ include file="/common/taglibs.jsp"%>
<title>Search</title>
<content tag="heading">
Search:
</content>
<FORM method="GET">
        <spring:bind path="command.query">
                <INPUT type="text" size="20" name="query" value="<c:out
value="${status.value}"/> " />
        </spring:bind>

        <P />
                <INPUT type="submit" value="Search" />
</FORM>
<p />
        <c:if test="${! empty searchResults}">
                <P />
                        Search took
                        <c:out value="${searchResults.searchTime}" />
                        ms
                <P />
                <TABLE border="2">
                        <TR>
                                <TH>
                                        SCORE
                                </TH>
                                <TH>
                                        TYPE
                                </TH>
                                <TH>
                                        ID
                                </TH>
                        </TR>

                        <c:forEach var="hit" items="${searchResults.hits}">
                                <P />
                                <TR>
                                        <TD>
                                                <fmt:formatNumber type="percent" value="${hit.score}" />
                                        </TD>
                                        <TD>
                                                <c:out value="${hit.alias}" />

                                        </TD>
                                        <TD>
                                                <c:out value="${hit.data.id}" />
                                        </TD>
                                </TR>
                        </c:forEach>
                </TABLE>

        </c:if>

c. Wire up the controllers – edit web/WEB-INF/action-servlet.xml and
add these beans:

        <bean id="searchController"
class="org.compass.spring.web.mvc.CompassSearchController">
                <property name="compass"><ref bean="compass"/></property>
                <property name="searchView"><value>searchView</value></property>
                <property name="searchResultsView"><value>searchResultsView</value></property>
                <property name="pageSize"><value>10</value></property>
        </bean>
        <!-- ====  COMPASS SEARCH CONTROLLER ==== -->

        <bean id="indexController"
class="org.compass.spring.web.mvc.CompassIndexController">
                <property name="compassGps"><ref bean="compassGps"/></property>
                <property name="indexView"><value>reindexView</value></property>
                <property name="indexResultsView"><value>reindexResultsView</value></property>
        </bean>

    <!-- View Resolver for JSPs -->
    <bean id="rbViewResolver"
class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
                <property name="basename"><value>views</value></property>
                <property name="order"><value>0</value></property>
        </bean>
d. Also add them into the urlMapping:
        <prop key="/search.html">searchController</prop>
<prop key="/reindex.html">indexController</prop>

e. Add a file views.properties under web/WEB-INF/classes containing:
searchView.class=org.springframework.web.servlet.view.JstlView
searchView.url=/WEB-INF/pages/search.jsp

searchResultsView.class=org.springframework.web.servlet.view.JstlView
searchResultsView.url=/WEB-INF/pages/search.jsp

reindexView.class=org.springframework.web.servlet.view.JstlView
reindexView.url=/WEB-INF/pages/reindex.jsp

reindexResultsView.class=org.springframework.web.servlet.view.JstlView
reindexResultsView.url=/WEB-INF/pages/reindex.jsp

f. Add in menu – edit menu-config in web/WEB-INF add the reindex to
the admin menu:
<Item name="ReIndex" title="menu.reindex" page="/reindex.html" roles="admin" />
g. add search to it's own menu:
        <Menu name="SearchMenu" title="menu.search" page="/search.html" wifth="60" />
h. now edit /web/pages/menu/jsp to add the new search menu:
<menu:displayMenu name="FileUpload"/>
<menu:displayMenu name="SearchMenu"/> <!--  ADDED LiNE -->
 <menu:displayMenu name="AdminMenu"/>
i. add the menu properties in
WEB-INF/classes/ApplicationResources.properties :
menu.search=Search
menu.reindex=Re-Index


Cheers
Chris

--
-------------------------------------------------
Christopher Barham
cbarham@...

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@...
For additional commands, e-mail: users-help@...

 « Return to Thread: search - integrate compass (lucene) and appfuse