笔记:lucene学习

news/2024/7/6 0:44:47

流程:

创建索引库:

1) 创建JavaBean对象

2) 创建Docment对象

3) 将JavaBean对象所有的属性值,均放到Document对象中去,属性名可以和JavaBean相同或不同

4) 创建IndexWriter对象

5) 将Document对象通过IndexWriter对象写入索引库中

6) 关闭IndexWriter对象

根据关键字查询索引库中的内容:

1) 创建IndexSearcher对象

2) 创建QueryParser对象

3) 创建Query对象来封装关键字

4) 用IndexSearcher对象去索引库中查询符合条件的前100条记录,不足100条记录的以实际为准

5) 获取符合条件的编号

6) 用indexSearcher对象去索引库中查询编号对应的Document对象

7) 将Document对象中的所有属性取出,再封装回JavaBean对象中去,并加入到集合中保存,以备将之用

实现:

步一:创建manven工程,取名叫search-lucene

步二:导入依赖

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>cn.it.lucene</groupId>
	<artifactId>search-lucene</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>
	<!-- 集中定义依赖版本号 -->
	<properties>
		<junit.version>4.10</junit.version>
		<spring.version>4.1.3.RELEASE</spring.version>
		<mybatis.version>3.2.8</mybatis.version>
		<mybatis.spring.version>1.2.2</mybatis.spring.version>
		<mybatis.paginator.version>1.2.15</mybatis.paginator.version>
		<mysql.version>5.1.32</mysql.version>
		<slf4j.version>1.6.4</slf4j.version>
		<jackson.version>2.4.2</jackson.version>
		<druid.version>1.0.9</druid.version>
		<httpclient.version>4.3.5</httpclient.version>
		<jstl.version>1.2</jstl.version>
		<servlet-api.version>2.5</servlet-api.version>
		<jsp-api.version>2.0</jsp-api.version>
		<commons-lang3.version>3.3.2</commons-lang3.version>
		<commons-io.version>1.3.2</commons-io.version>
		<lucene-version>3.0.2</lucene-version>
		<beanutils-version>1.8.0</beanutils-version>
		<pagehelper.version>3.7.5</pagehelper.version>
		<mapper.version>2.3.4</mapper.version>
	</properties>
	<dependencies>
		<!-- lucene依赖 -->
		<dependency>
			<groupId>org.apache.lucene</groupId>
			<artifactId>lucene-core</artifactId>
			<version>${lucene-version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.lucene</groupId>
			<artifactId>lucene-analyzers</artifactId>
			<version>${lucene-version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.lucene</groupId>
			<artifactId>lucene-highlighter</artifactId>
			<version>${lucene-version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.lucene</groupId>
			<artifactId>lucene-memory</artifactId>
			<version>${lucene-version}</version>
		</dependency>
		<!-- IKAnalyzer3.2.0Stable网上找不到依赖,自己下载后弄的 -->
		<dependency>
			<groupId>IKAnalyzer</groupId>
			<artifactId>IKAnalyzer3.2.0Stable</artifactId>
			<version>1.1</version>
		</dependency>
		<!-- 单元测试 -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>${junit.version}</version>
			<scope>test</scope>
		</dependency>
		<!-- Spring -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aspects</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<!-- Mybatis -->
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis</artifactId>
			<version>${mybatis.version}</version>
		</dependency>
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis-spring</artifactId>
			<version>${mybatis.spring.version}</version>
		</dependency>
		<!-- MySql -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>${mysql.version}</version>
		</dependency>

		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<version>${slf4j.version}</version>
		</dependency>

		<!-- Jackson Json处理工具包 -->
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
			<version>${jackson.version}</version>
		</dependency>

		<!-- 连接池 -->
		<dependency>
			<groupId>com.jolbox</groupId>
			<artifactId>bonecp-spring</artifactId>
			<version>0.8.0.RELEASE</version>
		</dependency>
		<!-- JSP相关 -->
		<dependency>
			<groupId>jstl</groupId>
			<artifactId>jstl</artifactId>
			<version>${jstl.version}</version>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>${servlet-api.version}</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jsp-api</artifactId>
			<version>${jsp-api.version}</version>
			<scope>provided</scope>
		</dependency>
		<!-- Apache工具组件 -->
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
			<version>${commons-lang3.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-io</artifactId>
			<version>${commons-io.version}</version>
		</dependency>
		<!-- beanutils -->
		<dependency>
			<groupId>commons-beanutils</groupId>
			<artifactId>commons-beanutils-core</artifactId>
			<version>${beanutils-version}</version>
		</dependency>
		<!-- 分页助手 -->
		<dependency>
			<groupId>com.github.pagehelper</groupId>
			<artifactId>pagehelper</artifactId>
			<version>${pagehelper.version}</version>
		</dependency>
		<dependency>
			<groupId>com.github.jsqlparser</groupId>
			<artifactId>jsqlparser</artifactId>
			<version>0.9.1</version>
		</dependency>
		<!-- 通用Mapper的依赖 -->
		<dependency>
			<groupId>com.github.abel533</groupId>
			<artifactId>mapper</artifactId>
			<version>${mapper.version}</version>
		</dependency>

	</dependencies>
</project>

步三:web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	id="MyWebApp" version="2.5">
	<display-name>lucene-search</display-name>

	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:spring/applicationContext*.xml</param-value>
	</context-param>
	<!--Spring的ApplicationContext 载入 -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	
	<!-- 添加编码过滤器,指定编码为UTF-8,解决POST请求的中文乱码 -->
	<filter>
		<filter-name>CharacterEncodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>CharacterEncodingFilter</filter-name>
		<url-pattern>/service/*</url-pattern>
	</filter-mapping>

	<!-- SpringMVC的入口 -->
	<servlet>
		<servlet-name>lucene-search</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:spring/lucene-search-servlet.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>lucene-search</servlet-name>
		<url-pattern>*.html</url-pattern>
	</servlet-mapping>
	<servlet-mapping>
		<servlet-name>lucene-search</servlet-name>
		<url-pattern>/service/*</url-pattern>
	</servlet-mapping>

	<welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>

</web-app>

步四:配置文件


mybatis-config.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
    PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
	<settings>
		<!-- 开启字段名和属性名驼峰似的匹配 -->
		<setting name="mapUnderscoreToCamelCase" value="true" />
		<!-- 开启延迟加载 -->
		<!-- <setting name="lazyLoadingEnabled" value="true"/> -->
		<!-- 按需延迟加载 -->
		<!-- <setting name="aggressiveLazyLoading" value="false"/> -->
	</settings>
	<!-- 分页插件 -->
	<plugins>
	    <plugin interceptor="com.github.pagehelper.PageHelper">
	        <property name="dialect" value="mysql"/>
	        <!-- 设置为true时,使用RowBounds分页会进行count查询 -->
	        <property name="rowBoundsWithCount" value="true"/>
	    </plugin>
	    
	    <plugin interceptor="com.github.abel533.mapperhelper.MapperInterceptor">
			<!-- 主键生成方式 -->
			<property name="IDENTITY" value="MYSQL" />
			<!-- 指定了Mapper接口 -->
			<property name="mappers" value="com.github.abel533.mapper.Mapper" />
		</plugin>
	</plugins>
	
	
</configuration>

applicationContext.xml:

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
	http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
	http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">

	<!-- 使用spring自带的占位符替换功能 -->
	<bean
		class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<!-- 允许JVM参数覆盖 -->
		<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
		<!-- 忽略没有找到的资源文件 -->
		<property name="ignoreResourceNotFound" value="true" />
		<!-- 配置资源文件 -->
		<property name="locations">
			<list>
				<value>classpath:jdbc.properties</value>
				<value>classpath:env.properties</value>
			</list>
		</property>
	</bean>
	<!-- 扫描包 -->
	<context:component-scan base-package="cn.it" />
	<!-- 定义数据源 -->
	<bean id="dataSource" class="com.jolbox.bonecp.BoneCPDataSource"
		destroy-method="close">
		<!-- 数据库驱动 -->
		<property name="driverClass" value="${jdbc.driver}" />
		<!-- 相应驱动的jdbcUrl -->
		<property name="jdbcUrl" value="${jdbc.url}" />
		<!-- 数据库的用户名 -->
		<property name="username" value="${jdbc.username}" />
		<!-- 数据库的密码 -->
		<property name="password" value="${jdbc.password}" />
		<!-- 检查数据库连接池中空闲连接的间隔时间,单位是分,默认值:240,如果要取消则设置为0 -->
		<property name="idleConnectionTestPeriod" value="60" />
		<!-- 连接池中未使用的链接最大存活时间,单位是分,默认值:60,如果要永远存活设置为0 -->
		<property name="idleMaxAge" value="30" />
		<!-- 每个分区最大的连接数 判断依据:请求并发数 -->

		<property name="maxConnectionsPerPartition" value="100" />
		<!-- 每个分区最小的连接数 -->
		<property name="minConnectionsPerPartition" value="5" />
	</bean>

	<!-- 定义Mybatis的SessionFactory -->
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="configLocation" value="classpath:mybatis/mybatis-config.xml" />
		<!-- <property name="mapperLocations" value="classpath:mybatis/mappers/**/*.xml" /> -->
	</bean>

	<!-- 扫描指定包下面的Mapper,并且自动注入到bean中 -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="basePackage" value="cn.it.lucene.mapper" />
	</bean>

	<!-- 定义事务管理器 -->
	<bean id="transactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>

	<!-- 定义事务策略 -->
	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<tx:attributes>
			<!--所有以query开头的方法都是只读的 -->
			<tx:method name="query*" read-only="true" />
			<!--其他方法使用默认事务策略 -->
			<tx:method name="*" />
		</tx:attributes>
	</tx:advice>

	<aop:config>
		<!--pointcut元素定义一个切入点,execution中的第一个星号 用以匹配方法的返回类型, 这里星号表明匹配所有返回类型。 com.abc.dao.*.*(..)表明匹配cn.itcast.mybatis.dao包下的所有类的所有 
			方法 -->
		<aop:pointcut id="myPointcut"
			expression="execution(* cn.it.lucene.service.*.*(..))" />
		<!--将定义好的事务处理策略应用到上述的切入点 -->
		<aop:advisor advice-ref="txAdvice" pointcut-ref="myPointcut" />
	</aop:config>

</beans>
lucene-search-servlet.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

	<!-- 注解驱动 -->
	<mvc:annotation-driven />

	<context:component-scan base-package="cn.it.lucene.controller" />

	<!-- Example: prefix="/WEB-INF/jsp/", suffix=".jsp", viewname="test" -> 
		"/WEB-INF/jsp/test.jsp" -->
	<bean
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/views/" />
		<property name="suffix" value=".jsp" />
	</bean>

</beans>
jdbc.properties:

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/taotao?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
jdbc.username=root
jdbc.password=root
env.properties:里面没东西
步五:用于测试的表,数据库名为taotao,下面为sql创建表

CREATE TABLE `tb_item` (
  `id` bigint(20) NOT NULL auto_increment COMMENT '商品id,同时也是商品编号',
  `title` varchar(100) NOT NULL COMMENT '商品标题',
  `sell_point` varchar(500) default NULL COMMENT '商品卖点',
  `price` bigint(20) NOT NULL COMMENT '商品价格,单位为:分',
  `num` int(10) NOT NULL COMMENT '库存数量',
  `barcode` varchar(30) default NULL COMMENT '商品条形码',
  `image` varchar(500) default NULL COMMENT '商品图片',
  `cid` bigint(10) NOT NULL COMMENT '所属类目,叶子类目',
  `status` tinyint(4) NOT NULL default '1' COMMENT '商品状态,1-正常,2-下架,3-删除',
  `created` datetime NOT NULL COMMENT '创建时间',
  `updated` datetime NOT NULL COMMENT '更新时间',
  PRIMARY KEY  (`id`),
  KEY `cid` (`cid`),
  KEY `status` (`status`),
  KEY `updated` (`updated`)
) ENGINE=InnoDB AUTO_INCREMENT=1474391931 DEFAULT CHARSET=utf8 COMMENT='商品表'
步六:java类


BasePojo:

package cn.it.lucene.pojo;

import java.util.Date;

public abstract class BasePojo {
    
    private Date created;
    private Date updated;
    public Date getCreated() {
        return created;
    }
    public void setCreated(Date created) {
        this.created = created;
    }
    public Date getUpdated() {
        return updated;
    }
    public void setUpdated(Date updated) {
        this.updated = updated;
    }
}
Item:

package cn.it.lucene.pojo;

import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import org.apache.commons.lang3.StringUtils;

/**
 * 商品
 *
 */
@Table(name = "tb_item")
public class Item extends BasePojo {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;// 商品id,同时也是商品编号

    private String title;// 商品标题

    private String sellPoint;// 商品卖点

    private Long price;// 商品价格,单位为:分

    private String image;// 商品图片

    private Long cid;// 所属类目,叶子类目

    private Integer status;// 商品状态,1-正常,2-下架,3-删除

    private Integer num;// 库存数量

    private String barcode;// 商品条形码

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getSellPoint() {
        return sellPoint;
    }

    public void setSellPoint(String sellPoint) {
        this.sellPoint = sellPoint;
    }

    public Integer getNum() {
        return num;
    }

    public void setNum(Integer num) {
        this.num = num;
    }

    public String getBarcode() {
        return barcode;
    }

    public void setBarcode(String barcode) {
        this.barcode = barcode;
    }

    public Long getPrice() {
        return price;
    }

    public void setPrice(Long price) {
        this.price = price;
    }

    public String getImage() {
        return image;
    }

    public void setImage(String image) {
        this.image = image;
    }

    public Long getCid() {
        return cid;
    }

    public void setCid(Long cid) {
        this.cid = cid;
    }

    public Integer getStatus() {
        return status;
    }

    public void setStatus(Integer status) {
        this.status = status;
    }

    public String[] getImages() {
        return this.getImage() == null ? null : StringUtils.split(this.getImage(), ',');
    }

    @Override
    public String toString() {
        return "Item [id=" + id + ", title=" + title + ", sellPoint=" + sellPoint + ", price=" + price
                + ", image=" + image + ", cid=" + cid + ", status=" + status + "]";
    }

}

ItemMapper:

package cn.it.lucene.mapper;

import cn.it.lucene.pojo.Item;

import com.github.abel533.mapper.Mapper;

public interface ItemMapper extends Mapper<Item>{

}
LuceneUtil:

package cn.it.lucene.util;

import java.io.File;
import java.lang.reflect.Method;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.cjk.CJKAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.Index;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.index.IndexWriter.MaxFieldLength;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.wltea.analyzer.lucene.IKAnalyzer;

/**
 * 工具类
 * 
 * @author yeheng
 */
public class LuceneUtil {
    public static final String DIRECTORYS = "E:/IndexDB";

    private static Directory directory; // 目录

    private static Version version; // 版本

    private static Analyzer analyzer; // 分词

    private static MaxFieldLength maxFieldLength; // 最大文件长度

    static {
        try {
            directory = FSDirectory.open(new File(DIRECTORYS));
            version = Version.LUCENE_30;
            analyzer = new IKAnalyzer(); // 使用第三方分词器IKAnalyzer
//            analyzer = new CJKAnalyzer(version);
            maxFieldLength = MaxFieldLength.LIMITED;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    public static Directory getDirectory() {
        return directory;
    }

    public static Version getVersion() {
        return version;
    }

    public static Analyzer getAnalyzer() {
        return analyzer;
    }

    public static MaxFieldLength getMaxFieldLength() {
        return maxFieldLength;
    }

    private LuceneUtil() {
    }

    /**
     * 将JavaBean转成Document对象
     * 
     * @param obj 实体对象JavaBean
     * @return Document对象
     * @throws Exception
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public static Document javabean2document(Object obj) throws Exception {
        // 创建Docuemnt对象
        Document document = new Document();
        // 获取obj引用的对象字节码
        Class clazz = obj.getClass();
        // 通过对象字节码获取私有的属性
        java.lang.reflect.Field[] reflectFields = clazz.getDeclaredFields();
        // 迭代
        for (java.lang.reflect.Field reflectField : reflectFields) {
            // 强力反射
            reflectField.setAccessible(true);
            // 获取属性名
            String name = reflectField.getName();
            // 人工拼接方法名
            String methodName = "get" + name.substring(0, 1).toUpperCase() + name.substring(1);
            // 获取方法,例如:getId()/getTitle()/getContent()
            Method method = clazz.getMethod(methodName, null);
            String value=null;
            if (!org.springframework.util.StringUtils.isEmpty(method.invoke(obj, null))) {

                // 执行方法
                value = method.invoke(obj, null).toString();
            }else{
//                value="1";
                continue;
            }
            // 加入到Document对象中去,这时javabean的属性与document对象的属性相同
            document.add(new Field(name, value, Store.YES, Index.ANALYZED));
        }
        // 返回document对象
        return document;
    }

    /**
     * 将Document对象转成JavaBean对象
     * 
     * @param document Document对象
     * @param clazz 对象字节码
     * @return 实体对象JavaBean
     * @throws Exception
     */
    @SuppressWarnings("rawtypes")
    public static Object document2javabean(Document document, Class clazz) throws Exception {
        Object obj = clazz.newInstance();
        // 通过对象字节码获取私有的属性
        java.lang.reflect.Field[] reflectFields = clazz.getDeclaredFields();
        for (java.lang.reflect.Field reflectField : reflectFields) {
            // 强力反射
            reflectField.setAccessible(true);
            // 获取属性名 例如 id/title/content
            String name = reflectField.getName();
            // 获取对应的值
            String value = document.get(name);
            // 封装javabean对应的属性中去,通过setXxx()方法
            BeanUtils.setProperty(obj, name, value);
        }
        return obj;
    }

}

PageInfo:

package cn.it.lucene.bean;

import java.util.List;

public class PageInfo<T> {

    private Long total;

    private List<T> rows;

    public PageInfo() {

    }
    
    public PageInfo(Long total, List<T> rows) {
        this.total = total;
        this.rows = rows;
    }

    public Long getTotal() {
        return total;
    }

    public void setTotal(Long total) {
        this.total = total;
    }

    public List<T> getRows() {
        return rows;
    }

    public void setRows(List<T> rows) {
        this.rows = rows;
    }

}

BaseService:

package cn.it.lucene.service;

import java.util.Date;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;

import cn.it.lucene.pojo.BasePojo;

import com.github.abel533.entity.Example;
import com.github.abel533.mapper.Mapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;

public abstract class BaseService<T extends BasePojo> {

    /** 由子类实现该方法,返回具体的Mapper的实现类 **/
//    public abstract Mapper<T> getMapper();
    
    @Autowired
    private Mapper<T> mapper;
    
    public Mapper<T> getMapper() {
        return mapper;
    }

    /**
     * 根据主键id查询数据
     * 
     * @param id
     * @return
     */
    public T queryById(Long id) {
        return this.mapper.selectByPrimaryKey(id);
    }

    /**
     * 查询所有数据
     * 
     * @return
     */
    public List<T> queryAll() {
        return this.mapper.select(null);
    }

    /**
     * 根据条件查询数据集合
     * 
     * @param t
     * @return
     */
    public List<T> queryByWhere(T t) {
        return this.mapper.select(t);
    }

    /**
     * 根据条件查询一条数据
     * 
     * @param t
     * @return
     */
    public T queryOne(T t) {
        return this.mapper.selectOne(t);
    }

    /**
     * 分页查询数据
     * 
     * @param t
     * @param page
     * @param rows
     * @return
     */
    public PageInfo<T> queryPageListByWhere(T t, Integer page, Integer rows) {
        PageHelper.startPage(page, rows, true);// 设置分页参数
        // 查询数据
        List<T> list = this.queryByWhere(t);
        return new PageInfo<T>(list);
    }
    
    /**
     * 自定义查询条件,分页查询
     * 
     * @param example
     * @param page
     * @param rows
     * @return
     */
    public PageInfo<T> queryPageListByExample(Example example, Integer page, Integer rows) {
        PageHelper.startPage(page, rows, true);// 设置分页参数
        // 查询数据
        List<T> list = this.mapper.selectByExample(example);
        return new PageInfo<T>(list);
    }

    /**
     * 新增数据
     * 
     * @param t
     * @return
     */
    public Integer save(T t) {
        t.setCreated(new Date());
        t.setUpdated(t.getCreated());
        return this.mapper.insert(t);
    }

    /**
     * 新增数据,使用不为null的字段
     * 
     * @param t
     * @return
     */
    public Integer saveSelective(T t) {
        t.setCreated(new Date());
        t.setUpdated(t.getCreated());
        return this.mapper.insertSelective(t);
    }

    /**
     * 更新数据
     * 
     * @param t
     * @return
     */
    public Integer update(T t) {
        t.setUpdated(new Date());
        return this.mapper.updateByPrimaryKey(t);
    }

    /**
     * 更新数据,使用不为null的字段
     * 
     * @param t
     * @return
     */
    public Integer updateSelective(T t) {
        t.setUpdated(new Date());
        return this.mapper.updateByPrimaryKeySelective(t);
    }

    /**
     * 更加主键id删除数据
     * 
     * @param id
     * @return
     */
    public Integer deleteById(Long id) {
        return this.mapper.deleteByPrimaryKey(id);
    }

    /**
     * 批量删除
     * 
     * @param ids
     * @param property
     * @param clazz
     * @return
     */
    public Integer deleteByIds(List<Object> ids, String property, Class<T> clazz) {
        Example example = new Example(clazz);
        example.createCriteria().andIn(property, ids);
        return this.mapper.deleteByExample(example);
    }

}

ItemService:(核心代码)

package cn.it.lucene.service;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import org.apache.lucene.document.Document;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryParser.MultiFieldQueryParser;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.highlight.Formatter;
import org.apache.lucene.search.highlight.Highlighter;
import org.apache.lucene.search.highlight.QueryScorer;
import org.apache.lucene.search.highlight.Scorer;
import org.apache.lucene.search.highlight.SimpleHTMLFormatter;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.RAMDirectory;
import org.springframework.stereotype.Service;

import cn.it.lucene.bean.PageInfo;
import cn.it.lucene.pojo.Item;
import cn.it.lucene.util.LuceneUtil;


@Service
public class ItemService extends BaseService<Item> {
    // 根据什么字段搜索
    private static final String[] ARRAY = { "id", "title", "sellPoint", "price", "cid", "status" };
    //最多显示的条数
    private static final Integer COUNT=500;

    /**
     * 增加document对象到索引库中
     * 
     * @throws Exception
     */
    public void addItemLucene() throws Exception {
        // 从数据库中找出所有item
        List<Item> list = super.queryAll();
        // for循环导入数据到索引库
        for (int i = 0; i < list.size(); i++) {

            // 将JavaBean转成Document对象
            Document document = LuceneUtil.javabean2document(list.get(i));

            // 硬盘索引库
            Directory fsDirectory = FSDirectory.open(new File(LuceneUtil.DIRECTORYS));

            // 内存索引库,因为硬盘索引库的内容要同步到内存索引库中
            Directory ramDirectory = new RAMDirectory(fsDirectory);

            // 指向硬盘索引库的字符流,true表示如果内存索引库中和硬盘索引库中的相同的document对象时,先删除硬盘索引库中的document对象,
            // 再将内存索引库的document对象写入硬盘索引库中
            // 反之是false,默认为false,这个boolean值写在硬盘字符流的构造器
            IndexWriter fsIndexWriter = new IndexWriter(fsDirectory, LuceneUtil.getAnalyzer(), true,
                    LuceneUtil.getMaxFieldLength());

            // 指向内存索引库的字符流
            IndexWriter ramIndexWriter = new IndexWriter(ramDirectory, LuceneUtil.getAnalyzer(),
                    LuceneUtil.getMaxFieldLength());
            //人工设置该document的得分 走后门
            //document.setBoost(100F);
            // 将document对象写入内存索引库
            ramIndexWriter.addDocument(document);
          //设置合并因子,即满足100个cfs文本一合并
            ramIndexWriter.setMergeFactor(100);
            ramIndexWriter.close();

            // 将内存索引库的所有document对象同步到硬盘索引库中
            fsIndexWriter.addIndexesNoOptimize(ramDirectory);
            //设置合并因子,即满足100个cfs文本一合并
            fsIndexWriter.setMergeFactor(100);
            //关闭流
            fsIndexWriter.close();
        }
    }

    /**
     * 根据关键字,从索引库中查询记录
     * @param keywords 关键字
     * @param page 页数
     * @param rows 一页条数
     * @return PageInfo<Item>
     * @throws Exception
     */
    @SuppressWarnings("resource")
    public PageInfo<Item> findAllLucene(String keywords,Integer page, Integer rows) throws Exception {
        List<Item> articleList = new ArrayList<Item>();
        // //单字段搜索
        // QueryParser queryParser = new QueryParser(LuceneUtil.getVersion(), "title",
        // LuceneUtil.getAnalyzer());

        // 多字段搜索,好处:搜索的范围大,最大限度匹配搜索结果
        QueryParser queryParser = new MultiFieldQueryParser(LuceneUtil.getVersion(), ARRAY,
                LuceneUtil.getAnalyzer());
        Query query = queryParser.parse(keywords);
        IndexSearcher indexSearcher = new IndexSearcher(LuceneUtil.getDirectory());

        // 按得分度高低排序
        TopDocs topDocs = indexSearcher.search(query, COUNT);

        // 创建排序对象
        // 参数一:id表示依据document对象中的哪个字段排序,例如:id
        // 参数二:SortField.INT表示document对象中该字段的类型,以常量方式书写
        // 参数三:true表示降序,类似于order by id desc
        // 参数三:false表示升序,类似于order by id asc
        // Sort sort = new Sort(new SortField("id",SortField.INT,false));

        // 按count字段的降序排列,如果count字段相同的话,再按id的升序排序
        // Sort sort = new Sort(new SortField("count", SortField.INT, true), new SortField("id",
        // SortField.INT,
        // false));

        // sort表示排序的条件
        // TopDocs topDocs = indexSearcher.search(query, null, 100, sort);

        // 格式对象
        Formatter formatter = new SimpleHTMLFormatter("<font color='red'>", "</font>");
        // 关键字对象
        Scorer scorer = new QueryScorer(query);
        // 高亮对象
        Highlighter highlighter = new Highlighter(formatter, scorer);

        for (int i = 0; i < topDocs.scoreDocs.length; i++) {
            ScoreDoc scoreDoc = topDocs.scoreDocs[i];
            int no = scoreDoc.doc;
          //获取document对象的评分
//            float score = scoreDoc.score;
//            System.out.println("score=" + score);
            // 关键字没有高亮
            Document document = indexSearcher.doc(no);
            
            //for循环让关键字高亮
            for (int j = 0; j < ARRAY.length; j++) {
                String highlighterField=null;
                if(document.get(ARRAY[j])!=null){
                    // 关键字高亮
                    highlighterField = highlighter.getBestFragment(LuceneUtil.getAnalyzer(), ARRAY[j],
                            document.get(ARRAY[j]));
                }
                 if(highlighterField!=null){
                     // 将高亮后的结果再次封装到document对象中
                     document.getField(ARRAY[j]).setValue(highlighterField);
                 }
            }
            Item item = (Item) LuceneUtil.document2javabean(document, Item.class);
            articleList.add(item);
        }
//        PageHelper.startPage(page, rows, true);// 设置分页参数
        return new PageInfo<Item>(Long.valueOf(COUNT),articleList);
//        return articleList;
    }
    /**
     * 删除所有索引库的内容
     * @throws Exception
     */
    public void deleteAllLucene() throws Exception{
            IndexWriter indexWriter = new IndexWriter(LuceneUtil.getDirectory(),LuceneUtil.getAnalyzer(),LuceneUtil.getMaxFieldLength());
            indexWriter.deleteAll();
            indexWriter.close();
    }
    /**
     * 根据id删除索引库的内容
     * @param id
     * @throws Exception
     */
    public void deleteLucene(Long id) throws Exception{
        Term term = new Term("id",String.valueOf(id));
        IndexWriter indexWriter = new IndexWriter(LuceneUtil.getDirectory(),LuceneUtil.getAnalyzer(),LuceneUtil.getMaxFieldLength());
        indexWriter.deleteDocuments(term);
        indexWriter.close();
    }
    /**
     * 根据id更新索引库的内容
     * @param id
     * @throws Exception
     */
    public void updateLucene(Long id) throws Exception{
        Item item=super.queryById(id);
        Document document = LuceneUtil.javabean2document(item);
        Term term = new Term("id",String.valueOf(id));
        IndexWriter indexWriter = new IndexWriter(LuceneUtil.getDirectory(),LuceneUtil.getAnalyzer(),LuceneUtil.getMaxFieldLength());
        indexWriter.updateDocument(term,document);
        indexWriter.close();
    }
}
ItemSearchController:

package cn.it.lucene.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import cn.it.lucene.bean.PageInfo;
import cn.it.lucene.pojo.Item;
import cn.it.lucene.service.ItemService;


/**
 * 商品搜索
 */

@Controller
public class ItemSearchController {
    private static final Logger LOGGER = LoggerFactory.getLogger(ItemSearchController.class);

    @Autowired
    private ItemService itemService;

    /**
     * 根据关键字查询数据,跳转到search视图
     * @param keyword
     * @param page
     * @param rows
     * @return
     */
    @RequestMapping(value = "search", method = RequestMethod.GET)
    public ModelAndView search(@RequestParam("keyword") String keyword,
            @RequestParam(value = "page", defaultValue = "1") Integer page,
            @RequestParam(value = "rows", defaultValue = "28") Integer rows) {

        ModelAndView mv = new ModelAndView("search");
        mv.addObject("query", keyword);
        mv.addObject("page", page);
        try {
            PageInfo<Item> pageInfo=this.itemService.findAllLucene(keyword, page, rows);
            mv.addObject("itemList", pageInfo.getRows());
            mv.addObject("pages", (pageInfo.getTotal() + rows - 1) / rows);
        } catch (Exception e) {
            LOGGER.error("根据关键字从索引库中获取数据失败,关键字:"+keyword,e);
        }
        return mv;
    }

}
步7:测试导入数据

ItemServiceTest:

package cn.it.lucene.service.test;

import java.util.List;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import cn.it.lucene.bean.PageInfo;
import cn.it.lucene.pojo.Item;
import cn.it.lucene.service.ItemService;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring/applicationContext*.xml"})
public class ItemServiceTest {
    @Autowired
    private ItemService itemService;

    /**
     * 测试导入数据
     * @throws Exception
     */
    @Test
    public void add() throws Exception {
        this.itemService.addItemLucene();
    }
    @Test
    public void query() throws Exception {
        PageInfo<Item> page=this.itemService.findAllLucene("小米",1,10);
        List<Item> list=page.getRows();
        for(Item item:list){
            
            System.out.println(item);
        }
    }

}
步八:视图

视图这里省略


步九:启动tomcat访问路径http://127.0.0.1:8080/search-lucene/search.html?keyword=小米,效果如下:





http://www.niftyadmin.cn/n/2455061.html

相关文章

抓包工具Charles简单使用介绍

一是拦截别人软件的发送的请求和后端接口&#xff0c;练习开发。二是自己后端返回的response拦截修改后再接收以达到测试临界数据的作用。三写脚本重复拦截抓取别人的数据。四支持流量控制&#xff0c;可以模拟慢速网络以及等待时间&#xff08;latency&#xff09;较长的请求。…

基于cygwin构建u-boot(五)结尾:shell 工具

结尾&#xff0c;基于cygwin对u-boot的处理&#xff0c;很大一部分都是再处理 路径等相关的问题&#xff0c;只有一个涉及到gcc的参数配置。 为了达到顺利编译的目的&#xff0c;使用shell下的部分工具进行处理。 1、sed sed简单说&#xff0c;是一种按照特定处理方式&#xff…

笔记:shiro与spring整合

官方网站&#xff1a;http://shiro.apache.org/spring.html 视频来自于&#xff1a;http://www.java1234.com/ 1.建表&#xff1a;用户表t_user、角色表t_role、权限表t_permission CREATE DATABASE test ;USE test;DROP TABLE IF EXISTS t_permission;CREATE TABLE t_permis…

笔记:CXF与spring整合

webService服务地址&#xff1a;http://www.webxml.com.cn 一&#xff1a;接收服务 步骤&#xff1a;得到服务地址----wsimport代理-------打jar包------放到项目中-------通过wsdl元素调用相关的方法得到数据 wsdl描述图&#xff1a; - wsimport 命令的位置&#xff1a; …

XMPP即时通讯资料记录

几天开始研究XMPP即时通讯的技术&#xff0c;来实现移动应用的计时聊天功能。记录下参考的博客地址&#xff0c;还挺详细的。 http://blog.csdn.net/fhbystudy/article/details/16117561 http://blog.sina.com.cn/s/blog_aef8b52701019sle.html 转载于:https://www.cnblogs.com…

springboot-logback

springboot logback配置 1.pattern解析&#xff1a; %d{yyyy-MM-ddTHH:mm:ss.SSSXXX}   带时区的时间 %level   日志级别 [%thread]   线程名 [%logger{50}:%line]   打印日志对应的方法和行数  [uuid:%X{operation_id}]   这个是logback的MDC机制&#xff0c;没有…

重建索引报错-python数据分析

obj3 pd.Series([blue, purple, yellow], index[0, 2, 4]) obj3.reindex(range(6), methodffill) 此时会爆出一大堆错误。 出错原因是&#xff1a;之前 obj3 的索引是字符串类型&#xff0c;重新索引是 range&#xff0c;int 类型。这样数据类型不一样&#xff0c;导致出错 修…

笔记:后台设置网站广告

可以参考的内容&#xff1a;kingEditor单文件上传组件使用&#xff0c;表单批量提交及其优化&#xff0c;图片预览效果&#xff0c;数据回显 效果图&#xff1a; jsp页面&#xff1a;sitead.jsp <% page language"java" import"java.util.*" pageEncod…