Java search搜索的demo

之前写的有关搜索的dmeo,记录一下,如果有问题不负责

       创建一个springboot的项目

     pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>searchdemo</artifactId>
    <version>0.0.1</version>
    <name>searchdemo</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
        <lucene.version>7.7.3</lucene.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <!--热部署-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <!--Druid数据连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.9</version>
        </dependency>

        <!-- mysql connector数据库驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!--mybatis-puls-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.3.0</version>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!-- 实现web功能依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- lucene -->
        <!-- 添加lucene支持 -->
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-core</artifactId>
            <version>${lucene.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-queryparser</artifactId>
            <version>${lucene.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-analyzers-common</artifactId>
            <version>${lucene.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-highlighter</artifactId>
            <version>${lucene.version}</version>
        </dependency>
        <!--        lucene-->
        <!--        ik分词·-->
        <dependency>
            <groupId>com.janeluo</groupId>
            <artifactId>IKAnalyzer</artifactId>
            <version>2017_6_6_0</version>
        </dependency>
        <!--支持拼音-->
        <dependency>
            <groupId>com.github.open-android</groupId>
            <artifactId>pinyin4j</artifactId>
            <version>2.5.0</version>
        </dependency>
        <!--工具封装类-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.5.7</version>
        </dependency>

        <dependency>
            <groupId>com.github.open-android</groupId>
            <artifactId>pinyinAnalyzer</artifactId>
            <version>4.3.1</version>
        </dependency>
        <dependency>
            <groupId>com.github.open-android</groupId>
            <artifactId>pinyinTokenFilter</artifactId>
            <version>1.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!--dto-->
        <dependency>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-annotations</artifactId>
            <version>1.6.1</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.1</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

application.properties

#解决乱码问题
spring.http.encoding.force=true
spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
server.tomcat.uri-encoding=UTF-8
package com.example.searchdemo.search.controller;

import java.util.List;

import com.example.searchdemo.search.IndexDemo;
import com.example.searchdemo.search.model.PersonTable;
import com.example.searchdemo.search.api.CommonResult;
import com.example.searchdemo.search.service.PersonTableService;
import com.example.searchdemo.search.utils.GenerateIdCard;
import com.example.searchdemo.search.utils.RandInfo;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.TextField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;

/**
 * @author l
 * @version 1.0
 * @PACKAGE_NAME: com.example.searchdemo.search
 * @date 2021/4/28 15:21 周三
 */

@RestController
public class DataBaseController {

    @Autowired
    PersonTableService personTableService;
    @Autowired
    IndexDemo indexDemo;

    @GetMapping("/createIndex")
    public String createIndex() {
        //查询数据库,必须要批量查询
        //每拉取一次数据
        List<PersonTable> queryFood = personTableService.lists();
        //获取字段
        for (int i = 0; i < queryFood.size(); i++) {
            //获取每行数据
            PersonTable personTable = new PersonTable();
            personTable.setPersonId(queryFood.get(i).getPersonId());
            personTable.setPersonName(queryFood.get(i).getPersonName());
            personTable.setIdentityNo(queryFood.get(i).getIdentityNo());
            //创建Document对象
            Document doc = new Document();
            //获取每列数据
            Field foodid = new Field("personId", personTable.getPersonId().toString(), TextField.TYPE_STORED);
            Field foodname = new Field("personName", personTable.getPersonName(), TextField.TYPE_STORED);
            Field price = new Field("identityNo", personTable.getIdentityNo().toString(), TextField.TYPE_STORED);
            //添加到Document中
            doc.add(foodid);
            doc.add(foodname);
            doc.add(price);
            //调用,创建索引库
            indexDemo.write(doc);
        }
        return "成功";
    }

    /**
     * 搜索
     * @param keyWord
     * @return
     */
    @GetMapping("/searchFood")
    public CommonResult getFood(String keyWord) {
        return indexDemo.searchssss(keyWord);
    }

    /**
     * 随机生成人员信息
     */
    @GetMapping("/addPon")
    public void addPon() {
        RandInfo rand = new RandInfo();
        PersonTable person = new PersonTable();
        GenerateIdCard g = new GenerateIdCard();
        for (int i = 1; i <= 5000; i++) {
            //在此控制生成的数量(如10个),按实际情况来
            //为了防止有空格,取代空格
            String idnum = g.generate().replace(" ", "");
            String familyName = rand.getFamilyName();
            String[] nameAndSex = rand.getNameAndSex(rand.getSex());
            String name = nameAndSex[0];
            String sex = nameAndSex[1];
            int age = rand.getAge();
            person.setPersonName(familyName.concat(name));
            person.setSex(sex);
            //过滤掉位数不够18位的
            if (idnum.length() == 18) {
                person.setIdentityNo(idnum);
            }
            person.setAge(age);
            personTableService.addPon(person);
//            System.out.println(person);
        }


    }


    @RequestMapping("/searchs")
    public ModelAndView searchs() {
        ModelAndView view = new ModelAndView();
        view.setViewName("search");
        return view;
    }
}
package com.example.searchdemo.search.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.example.searchdemo.search.model.PersonTable;

import java.util.List;


/**
 * @author l
 * @version 1.0
 * @PACKAGE_NAME: com.dlax.dfms.base.service
 * @date 2021/4/16 14:18 周五
 */
public interface PersonTableService extends IService<PersonTable> {

    List<PersonTable> lists();

    void addPon(PersonTable person);
}
package com.example.searchdemo.search.service.Impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.searchdemo.search.model.PersonTable;
import com.example.searchdemo.search.dao.PersonTableMapper;
import com.example.searchdemo.search.service.PersonTableService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * @author l
 * @version 1.0
 * @PACKAGE_NAME: com.dlax.dfms.base.service.impl.access
 * @date 2021/4/16 14:27 周五
 */
@Slf4j
@Service
@Transactional(rollbackFor = RuntimeException.class)
public class PersonTableServiceImpl extends ServiceImpl<PersonTableMapper, PersonTable> implements PersonTableService {

    @Autowired
    PersonTableMapper personTableMapper;


    @Override
    public List<PersonTable> lists() {
        return personTableMapper.lists();
    }

    @Override
    public void addPon(PersonTable person) {
        personTableMapper.insertpon(person);
    }
}
package com.example.searchdemo.search.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.searchdemo.search.model.PersonTable;
import org.springframework.stereotype.Repository;

import java.util.List;

/**
 * <p>
 *  Mapper 接口
 * </p>
 *
 * @author 
 * @since 2021-04-16
 */
@Repository
public interface PersonTableMapper extends BaseMapper<PersonTable> {

    List<PersonTable> lists();

    void insertpon(PersonTable person);
}
package com.example.searchdemo.search.model;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

import java.io.Serializable;

@Data
@TableName("db.persontable")
public class PersonTable implements Serializable {

     private static final long serialVersionUID = 1L;

    @TableField("person_id")
    private Integer personId;
    @TableField("person_name")
    private String personName;
    @TableField("identity_no")
    private String identityNo;

    private String sex;
    private Integer age;
}
自定义分词Analyzer:中文分词+拼音分词

public class MyIkAnalyzer extends Analyzer {

    private final boolean userSmart;

    public MyIkAnalyzer(boolean userSmart){
        this.userSmart = userSmart;
    }
    @Override
    protected TokenStreamComponents createComponents(String s) {
        //ik userSmart=false 关闭智能分词 设置细颗粒分词
        Tokenizer tokenizer = new IKTokenizer(userSmart);
        //useSingle 支持数字 useItself 本身
        TokenStream tokenStream = new PinyinTokenFilter(new IKTokenFilter(tokenizer, true, true), true, true, 1);
        return new TokenStreamComponents(tokenizer, tokenStream);
    }
}
package com.example.searchdemo.search;

import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

import com.example.searchdemo.search.api.CommonResult;
import com.example.searchdemo.search.model.PersonTable;
import com.example.searchdemo.search.myAnalyse.MyIkAnalyzer;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.*;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.*;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.springframework.stereotype.Component;
import org.wltea.analyzer.lucene.IKAnalyzer;

/**
 * @author l
 * @version 1.0
 * @PACKAGE_NAME: com.example.searchdemo.search
 * @date 2021/4/28 15:03 周三
 */


@Component
public class IndexDemo {
    //Lucene索引文件路径
    static String dir = "C:\\lucence";
    //定义分词器
    static Analyzer analyzer = new IKAnalyzer();

    /**
     * 封裝一个方法,用于将数据库中的数据解析为一个个关键字词存储到索引文件中
     *
     * @param doc
     */
    public void write(Document doc) {
        try {
            //索引库的存储目录
            Directory directory = FSDirectory.open(Paths.get(dir));
            //关联当前lucence版本和分值器
            //创建分词
            Analyzer analyzer = new MyIkAnalyzer(false);
            IndexWriterConfig icw = new IndexWriterConfig(analyzer);
//            IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_7_7_3, analyzer);
            //传入目录和分词器
            IndexWriter iwriter = new IndexWriter(directory, icw);
            //写入到目录文件中
            iwriter.addDocument(doc);
            //提交事务
            iwriter.commit();
            //关闭流
            iwriter.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * 查询索引
     *
     * @param q 参数
     * @return 搜索结果
     */
    public CommonResult searchssss(String q) {
        long startTime = System.currentTimeMillis();
        Directory dir = null;
        IndexReader reader = null;
        try {
            String field = "personName";
            //索引库的存储目录
            Path indexPath = Paths.get("C:\\lucence");
            dir = FSDirectory.open(indexPath);
            reader = DirectoryReader.open(dir);
            IndexSearcher searcher = new IndexSearcher(reader);
            Analyzer analyzer = new IKAnalyzer(false, true, true);
            QueryParser parser = new QueryParser(field, analyzer);
            parser.setDefaultOperator(QueryParser.OR_OPERATOR);
            //去除空格,特殊字符处理
            String params = QueryParser.escape(q.replaceAll("\\s*", ""));
            //查询参数
            Query queryA = null;
            Query query = parser.parse(params);
            BooleanClause bc3 = new BooleanClause(query, BooleanClause.Occur.SHOULD);
            queryA = new BooleanQuery.Builder().add(bc3).build();
            System.out.println("Query:" + queryA);
            //获取上一页的最后一个元素
            ScoreDoc lastScoreDoc = getLastScoreDoc(1, 5, queryA, searcher);
            //通过最后一个元素搜索下页的pageSize个元素
            List<PersonTable> personTableList = new ArrayList<>();
            TopDocs topDocs = searcher.searchAfter(lastScoreDoc, queryA, 5);
            long totalHits = topDocs.totalHits;
            System.out.println("查询到的条数:" + totalHits);
            for (ScoreDoc sd : topDocs.scoreDocs) {
                Document doc = searcher.doc(sd.doc);
                PersonTable personTable = new PersonTable();
                personTable.setPersonId(Integer.valueOf(doc.get("personId")));
                personTable.setPersonName(doc.get("personName"));
                personTable.setIdentityNo(doc.get("identityNo"));
                personTableList.add(personTable);
                System.out.println(doc);
            }
            return CommonResult.success(personTableList, "查询成功", totalHits);
        } catch (Exception e) {
            return CommonResult.failed("查询异常");
        } finally {
            long endTime = System.currentTimeMillis();
            try {
                dir.close();
                reader.close();
            } catch (IOException e) {
                System.out.println("关流异常:" + e.getMessage());
            }
        }
    }


    /**
     * 根据页码和分页大小获取上一次最后一个ScoreDoc
     *
     * @param query         查询参数
     * @param indexSearcher 搜索
     * @return 最后一个ScoreDoc
     * @throws IOException io异常
     */
    private ScoreDoc getLastScoreDoc(int pageIndex, int pageSize, Query query, IndexSearcher indexSearcher) throws IOException {
        if (pageIndex == 1) {
            //如果是第一页返回空
            return null;
        }
        //获取上一页的数量
        int num = pageSize * (pageIndex - 1);
        TopDocs tds = indexSearcher.search(query, num);
        long nums = num - 1;
        if (nums < tds.totalHits) {
            return tds.scoreDocs[num - 1];
        }
        return null;
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

南大白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值