package com.boe.cim.teacher.luence;
import java.io.StringReader;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.cn.smart.SmartChineseAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermRangeQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.WildcardQuery;
import org.apache.lucene.search.highlight.Fragmenter;
import org.apache.lucene.search.highlight.Highlighter;
import org.apache.lucene.search.highlight.QueryScorer;
import org.apache.lucene.search.highlight.SimpleHTMLFormatter;
import org.apache.lucene.search.highlight.SimpleSpanFragmenter;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.search.NumericRangeQuery;
import com.boe.cim.teacher.pojo.RequirementInfo;
public class LuceneSearchRequirement {
/**
* @param indexreDir
* 索引文件路径path
* @param queryField
* 被索引字段 Field
* @param queryMsg
* 索引值
* @return
* @throws Exception
*/
public List<RequirementInfo> search(String indexreDir, String queryField, String queryMsg) throws Exception {
// 得到读取索引文件的路径
Directory dir = FSDirectory.open(Paths.get(indexreDir));
// 通过dir得到的路径下的所有的文件
// 建立索引查询器
IndexReader reader = DirectoryReader.open(dir);
IndexSearcher searcher = new IndexSearcher(reader);
// 中文分词器
SmartChineseAnalyzer analyzer = new SmartChineseAnalyzer();
// ======== 新增:日期范围查询处理 ========
Query dateQuery = null;
// TermRangeQuery dateQuery= null; ;
if ("requirementtime".equals(queryField)) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
long minTime = sdf.parse(queryMsg).getTime();
// dateQuery = LongPoint.newRangeQuery("time", minTime, Long.MAX_VALUE);
// dateQuery = TermRangeQuery.newStringRange("requirementtime", queryMsg, null, true, true);
dateQuery = NumericRangeQuery.newLongRange(
"requirementtime",
minTime,
Long.MAX_VALUE,
true, // 包含下界
true // 包含上界
);
}
// 建立查询解析器
/**
* 第一个参数是要查询的字段; 第二个参数是分析器Analyzer
*/
// QueryParser parser = new QueryParser(queryField, analyzer);
// 根据传进来的par查找
// Query query = parser.parse(queryMsg);
// Query query = new TermQuery(new Term("teacher",queryMsg));
// Query query = new WildcardQuery(new Term(queryField,"*"+queryMsg+"*"));
Query query;
//这四种类型需要特别匹配,不需要分词器进行搜索
if(queryField.equals("requirement") || queryField.equals("department") || queryField.equals("liaisonman") || queryField.equals("requirementtype") ) {
query = new WildcardQuery(new Term(queryField,"*"+queryMsg+"*"));
}else {
QueryParser parser = new QueryParser(queryField, analyzer);
query = parser.parse(queryMsg);
}
// 计算索引开始时间
long start = System.currentTimeMillis();
// ======== 新增:组合日期查询 ========
if (dateQuery != null) {
BooleanQuery.Builder builder = new BooleanQuery.Builder();
builder.add(query, BooleanClause.Occur.MUST);
builder.add(dateQuery, BooleanClause.Occur.MUST);
query = builder.build();
}
// // 计算索引开始时间
// long start = System.currentTimeMillis();
// 开始查询
/**
* 第一个参数是通过传过来的参数来查找得到的query; 第二个参数是要出查询的行数
*/
TopDocs topDocs = searcher.search(query, 104);
// 索引结束时间
long end = System.currentTimeMillis();
System.out.println("匹配:["+queryField+"]," + queryMsg + ",总共花费了" + (end - start) + "毫秒,共查到" + topDocs.totalHits + "条记录。");
// 高亮显示start
// 算分
QueryScorer scorer = new QueryScorer(query);
// 显示得分高的片段
Fragmenter fragmenter = new SimpleSpanFragmenter(scorer);
// 设置标签内部关键字的颜色
// 第一个参数:标签的前半部分;第二个参数:标签的后半部分。
SimpleHTMLFormatter simpleHTMLFormatter = new SimpleHTMLFormatter("<b><font color='red'>", "</font></b>");
// 第一个参数是对查到的结果进行实例化;第二个是片段得分(显示得分高的片段,即摘要)
Highlighter highlighter = new Highlighter(simpleHTMLFormatter, scorer);
// 设置片段
highlighter.setTextFragmenter(fragmenter);
// 高亮显示end
// 遍历topDocs
/**
* ScoreDoc:是代表一个结果的相关度得分与文档编号等信息的对象。 scoreDocs:代表文件的数组
*
* @throws Exception
*/
List<RequirementInfo> listinfo = new ArrayList<>();
for (ScoreDoc scoreDoc : topDocs.scoreDocs) {
RequirementInfo requirementinfo = new RequirementInfo();
// 获取文档
Document document = searcher.doc(scoreDoc.doc);
// 输出全路径
String id = document.get("id");
String queryType = document.get(queryField);
requirementinfo.setId(Integer.parseInt(id));
if (id != null) {
// 把全部得分高的摘要给显示出来
// 第一个参数是对哪个参数进行设置;第二个是以流的方式读入
TokenStream tokenStream = analyzer.tokenStream(queryField, new StringReader(queryType));
// 获取最高的片段
String highlighterString;
if(queryField.equals("requirement") || queryField.equals("department") || queryField.equals("liaisonman") || queryField.equals("requirementtype") ) {
highlighterString = queryType.replaceAll(queryMsg, "<b><font color='red'>"+queryMsg+"</font></b>");
}else {
highlighterString = highlighter.getBestFragment(tokenStream, queryType);
}
// String highlighterString = highlighter.getBestFragment(new SmartChineseAnalyzer(), queryField, queryType);
//设置高亮字段
switch (queryField) { // 根据搜索条件进行赋值
case "requirement": //需求名称
requirementinfo.setRequirement(highlighterString);
break;
case "department": //需求组织
requirementinfo.setDepartment(highlighterString);
break;
case "liaisonman": //需求联系人
requirementinfo.setLiaisonman(highlighterString);
break;
case "requirementtype": //需求类型
requirementinfo.setRequirementtype(Integer.parseInt(highlighterString.replaceAll("<[^>]+>", "")));
break;
case "requirementcontents": //需求内容
requirementinfo.setRequirementcontents(highlighterString);
break;
case "requirementbackground": //需求背景
requirementinfo.setRequirementbackground(highlighterString);
break;
}
listinfo.add(requirementinfo);
}
}
reader.close();
return listinfo;
}
}
package com.boe.cim.teacher.controller;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.boe.cim.teacher.dto.CommonOutPutResult;
import com.boe.cim.teacher.luence.LuceneSearchRequirement;
import com.boe.cim.teacher.pojo.RequirementInfo;
import com.boe.cim.teacher.service.RequirementInfoService;
import io.swagger.annotations.ApiOperation;
import net.sf.json.JSONObject;
@RestController
@RequestMapping("/requirement/select")
public class RequirementInfoSelectFunctionController {
@Value("${lucenere.indexre.dir}")
private String IndexreDir;
@Autowired
private RequirementInfoService requirementInfoService;
@GetMapping("/simpleselect")
@ApiOperation("简单搜索")
public CommonOutPutResult simpleselect(String FieldType, String queryMsg) {
try {
List<RequirementInfo> list = new LuceneSearchRequirement().search(IndexreDir, FieldType, queryMsg);
List<RequirementInfo> listResult = requirementInfoService.requirementInfoSelectResult(list);
List<List<RequirementInfo>> listTotal = new ArrayList<>();
JSONObject data = new JSONObject();
data.put("count", listResult.size());
data.put("page", Math.ceil((float) listResult.size() / 7));
ListIterator<RequirementInfo> lit = listResult.listIterator();
List<RequirementInfo> tempL = new ArrayList<>(10);
int index = 0;
// 把List中的需求信息分为 8 个一组 变成 List<List<RequirementInfo>>
while (lit.hasNext()) {
index++;
RequirementInfo tempT = lit.next();
tempL.add(tempT);
if (index == 7 || !lit.hasNext()) {// 7个
List<RequirementInfo> temp = new ArrayList<>(tempL);
listTotal.add(temp);
tempL.clear();
index = 0;
}
}
CommonOutPutResult result = new CommonOutPutResult(true, "搜索成功", "200", data);
result.setList(listTotal);
return result;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return new CommonOutPutResult(false, "搜索失败", "200", null);
}
@GetMapping("/highselect")
@ApiOperation("高级搜索功能")
public CommonOutPutResult highselect(@RequestParam(value = "requirement") String requirement,
@RequestParam(value = "department") String department,
@RequestParam(value = "liaisonman") String liaisonman,
@RequestParam(value = "requirementtype") String requirementtype,
@RequestParam(value = "requirementcontents") String requirementcontents) throws Exception {
// 不好判断是否是集合为空还是字段为空导致的结果
List<RequirementInfo> listRequirement = new ArrayList<>();
List<RequirementInfo> listDepartment = new ArrayList<>();
List<RequirementInfo> listLiaisonman = new ArrayList<>();
List<RequirementInfo> listRequirementtype = new ArrayList<>();
List<RequirementInfo> listRequirementcontents = new ArrayList<>();
// 需求列表
if (!requirement.equals("")) {
listRequirement = new LuceneSearchRequirement().search(IndexreDir, "requirement", requirement);
}
// 组织系别
if (!department.equals("")) {
listDepartment = new LuceneSearchRequirement().search(IndexreDir, "department", department);
}
// 联系人列表
if (!liaisonman.equals("")) {
listLiaisonman = new LuceneSearchRequirement().search(IndexreDir, "liaisonman", liaisonman);
}
// 需求类型
if (!requirementtype.equals("")) {
listRequirementtype = new LuceneSearchRequirement().search(IndexreDir, "requirementtype", requirementtype);
}
// 研究方向
if (!requirementcontents.equals("")) {
listRequirementcontents = new LuceneSearchRequirement().search(IndexreDir, "requirementcontents", requirementcontents);
}
// 需求列表
boolean setFirstList = false;
List<RequirementInfo> listTemp = new ArrayList<>();
if (!requirement.equals("")) { // 第一个只可能是赋值List
listTemp = listRequirement;
setFirstList = true;
}
// 组织系别
if (!department.equals("") && setFirstList) {
listTemp.retainAll(listDepartment);
//标红字段
for(int i=0;i<listTemp.size();i++) {
RequirementInfo requirementTemp = listTemp.get(i);
requirementTemp.setDepartment(listDepartment.get(listDepartment.indexOf(requirementTemp)).getDepartment());
listTemp.set(i, requirementTemp);
}
} else if (!department.equals("") && !setFirstList) {
listTemp = listDepartment;
}
// 需求联系人
if (!liaisonman.equals("") && setFirstList) {
listTemp.retainAll(listLiaisonman);
//标红字段
for(int i=0;i<listTemp.size();i++) {
RequirementInfo requirementTemp = listTemp.get(i);
requirementTemp.setLiaisonman(listLiaisonman.get(listLiaisonman.indexOf(requirementTemp)).getLiaisonman());
listTemp.set(i, requirementTemp);
}
} else if (!liaisonman.equals("") && !setFirstList) {
listTemp = listLiaisonman;
}
// 需求类型
if (!requirementtype.equals("") && setFirstList) {
listTemp.retainAll(listRequirementtype);
//标红字段
for(int i=0;i<listTemp.size();i++) {
RequirementInfo requirementTemp = listTemp.get(i);
requirementTemp.setRequirementtype(listRequirementtype.get(listRequirementtype.indexOf(requirementTemp)).getRequirementtype());
listTemp.set(i, requirementTemp);
}
} else if (!requirementtype.equals("") && !setFirstList) {
listTemp = listRequirementtype;
}
// 研究方向
if (!requirementcontents.equals("") && setFirstList) {
listTemp.retainAll(listRequirementcontents);
//标红字段
for(int i=0;i<listTemp.size();i++) {
RequirementInfo requirementTemp = listTemp.get(i);
requirementTemp.setRequirementcontents(listRequirementcontents.get(listRequirementcontents.indexOf(requirementTemp)).getRequirementcontents());
listTemp.set(i, requirementTemp);
}
} else if (!requirementcontents.equals("") && !setFirstList) {
listTemp = listRequirementcontents;
}
List<RequirementInfo> listResult = requirementInfoService.requirementInfoSelectResult(listTemp);
List<List<RequirementInfo>> listTotal = new ArrayList<>();
JSONObject data = new JSONObject();
data.put("count", listResult.size());
data.put("page", Math.ceil((float) listResult.size() / 7));
ListIterator<RequirementInfo> lit = listResult.listIterator();
List<RequirementInfo> tempL = new ArrayList<>(10);
int index = 0;
// 把List中的教师信息分为 8 个一组 变成 List<List<TeacherInfo>>
while (lit.hasNext()) {
index++;
RequirementInfo tempT = lit.next();
tempL.add(tempT);
if (index == 7 || !lit.hasNext()) {// 7个
List<RequirementInfo> temp = new ArrayList<>(tempL);
listTotal.add(temp);
tempL.clear();
index = 0;
}
}
CommonOutPutResult result = new CommonOutPutResult(true, "搜索成功", "200", data);
result.setList(listTotal);
return result;
}
@GetMapping("/allreqiurement")
@ApiOperation("获取所有需求")
public CommonOutPutResult getAllRequirements() {
List<RequirementInfo> requirements = requirementInfoService.getAllRequirements();
List<List<RequirementInfo>> listTotal = new ArrayList<>();
JSONObject data = new JSONObject();
data.put("count", requirements.size());
data.put("page", Math.ceil((float) requirements.size() / 7));
ListIterator<RequirementInfo> lit = requirements.listIterator();
List<RequirementInfo> tempL = new ArrayList<>(10);
int index = 0;
// 把List中的教师信息分为 8 个一组 变成 List<List<TeacherInfo>>
while (lit.hasNext()) {
index++;
RequirementInfo tempT = lit.next();
tempL.add(tempT);
if (index == 7 || !lit.hasNext()) {// 7个
List<RequirementInfo> temp = new ArrayList<>(tempL);
listTotal.add(temp);
tempL.clear();
index = 0;
}
}
CommonOutPutResult result = new CommonOutPutResult(true, "获取需求成功", "200", data);
result.setList(listTotal);
return result;
}
}
package com.boe.cim.teacher.service;
import java.util.List;
import com.boe.cim.teacher.dto.RequirementInfoUpdate;
import com.boe.cim.teacher.pojo.RequirementInfo;
import net.sf.json.JSONArray;
public interface RequirementInfoService {
RequirementInfo requirementInfoInsert(RequirementInfo requirementinfo)throws Exception;
JSONArray department();
String ChangeRequirementInfoFileList(String filename,String filetype,String id,String requirement)throws Exception;
//需求信息更新 ( 1.基本需求信息更新 2.详细需求信息更新 3.技术寻源更新 )
void updaterequirementinfo(RequirementInfoUpdate requirementInfoUpdate);
//返回一个经过处理后的需求List 符合搜索结果并且高亮字段
List<RequirementInfo> requirementInfoSelectResult(List<RequirementInfo> listOkRequirementInfo);
//返回一个所有的需求List
List<RequirementInfo> getAllRequirements() ;
void insertNewDepartment(String department)throws Exception;
}
package com.boe.cim.teacher.service.impl;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import com.boe.cim.teacher.dao.RequirementInfoMapper;
import com.boe.cim.teacher.dto.RequirementInfoUpdate;
import com.boe.cim.teacher.pojo.RequirementInfo;
import com.boe.cim.teacher.service.RequirementInfoService;
//import com.boe.cim.teacher.luence.LuceneIndexRequirement;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
@Service
public class RequirementInfoServiceImpl implements RequirementInfoService {
@Autowired
private RequirementInfoMapper requirementInfoMapper;
@Autowired
private StringRedisTemplate redisTemplate;
// @Value("${lucenere.indexre.dir}")
// private String IndexreDir;
// @Autowired
// private LuceneIndexRequirement LuceneIndexrequirement;
@Override
public RequirementInfo requirementInfoInsert(RequirementInfo requirementinfo) throws Exception {
// TODO Auto-generated method stub
try {
requirementInfoMapper.insertNewRequirementInfo(requirementinfo);
} catch (DuplicateKeyException e) {
e.printStackTrace();
throw new Exception("该需求已导入:" + e.getCause());
} catch (Exception e) {
e.printStackTrace();
throw new Exception("导入时发生未知错误,错误原因如下:" + e.getCause());
}
// System.out.println("requirementcontents = " + requirementinfo.getRequirementcontents());
// System.out.println("requirementcontents = " + requirementinfo.getTechnicalsource ());
// try {
// new LuceneIndexRequirement().indexSingleRequirement(IndexreDir, requirementinfo); // 调用新增方法
// } catch (Exception e) {
// e.printStackTrace();
// throw new Exception("新增需求索引更新失败" + e.getCause());
// }
redisTemplate.convertAndSend("requirementinfo",String.valueOf(requirementinfo.getId()));//将ID发送到队列中用于更新需求索引信息
return requirementInfoMapper.getRequirementInfoByUniquekey(requirementinfo);
}
@Override
public JSONArray department() {
// TODO Auto-generated method stub
JSONArray result = new JSONArray();
List<String> departments = requirementInfoMapper.distinctdepartment();
List<JSONObject> departmentResult = new ArrayList<>();
for (String department : departments) {
JSONObject departmentObject = new JSONObject();
departmentObject.put("value", department);
departmentResult.add(departmentObject);
}
result.add(departmentResult);
return result;
}
@Override
public String ChangeRequirementInfoFileList(String filename, String filetype, String id, String requirement)
throws Exception {
// TODO Auto-generated method stub
RequirementInfo requirementinfo = requirementInfoMapper.getRequirementByIdAndName(Integer.parseInt(id), requirement);
String updateFileString = "";
switch (filetype) {
case "附件":
String visitexcels = requirementinfo.getVisitexcel();
updateFileString = filenamedelete(filename, visitexcels);
try {
requirementInfoMapper.updateRequirementFileList(filetype, updateFileString, Integer.parseInt(id), requirement);
} catch (Exception e) {
e.printStackTrace();
throw new Exception("更新数据库文件列表失败,请联系管理员手动删除");
}
break;
}
return updateFileString;
}
String filenamedelete(String filename, String filenames) {
String[] files = filenames.split(";");
String result = "";
for (String fileSplitName : files) {
if (!filename.equals(fileSplitName))
result += fileSplitName + ";";
}
return result;
}
@Override
public void updaterequirementinfo(RequirementInfoUpdate requirementInfoUpdate) {
// TODO Auto-generated method stub
String type = requirementInfoUpdate.getType();
switch (type) {
case "基本信息":
requirementInfoMapper.updatenormalinfo(requirementInfoUpdate.getId(), requirementInfoUpdate.getRequirement(),
requirementInfoUpdate.getDepartment(),requirementInfoUpdate.getLiaisonman(), requirementInfoUpdate.getTelphone());
break;
case "详细信息":
requirementInfoMapper.updaterequirementdetail(requirementInfoUpdate.getId(), requirementInfoUpdate.getRequirement(),
requirementInfoUpdate.getRequirementbackground(), requirementInfoUpdate.getRequirementdescribe(),
requirementInfoUpdate.getRequirementcontents(), requirementInfoUpdate.getAcceptstandard(), requirementInfoUpdate.getBudget(),requirementInfoUpdate.getAssessment());
//只有科研能力才需要更新索引
// redisTemplate.convertAndSend("requirementinfoupdate",String.valueOf(requirementInfoUpdate.getId()));//将ID发送到队列中用于更新需求索引信息
break;
case "技术寻源":
requirementInfoMapper.updatecorporation(requirementInfoUpdate.getId(), requirementInfoUpdate.getRequirement(),requirementInfoUpdate.getTechnicalsource());
break;
}
redisTemplate.convertAndSend("requirementinfoupdate",String.valueOf(requirementInfoUpdate.getId()));//将ID发送到队列中用于更新需求索引信息
}
@Override
public List<RequirementInfo> requirementInfoSelectResult(List<RequirementInfo> listOkRequirementInfo) {
// TODO Auto-generated method stub
List<RequirementInfo> listAllrequirement =requirementInfoMapper.RequirementInfoCreateLuceneIndex();
List<RequirementInfo> listResultRequirementInfo = new ArrayList<>();
for(RequirementInfo requirementinfo : listOkRequirementInfo) {
RequirementInfo resultRequirementInfo = new RequirementInfo();
int index = listAllrequirement.indexOf(requirementinfo);
if(index < 0)continue;
resultRequirementInfo = listAllrequirement.get(index);
//高亮字段的赋值转移,处理的是能被搜索的字段
if(requirementinfo.getRequirement() != null) {
resultRequirementInfo.setRequirement(requirementinfo.getRequirement());
} if(requirementinfo.getLiaisonman() != null) {
resultRequirementInfo.setLiaisonman(requirementinfo.getLiaisonman());
} if(requirementinfo.getRequirementbackground() != null) {
resultRequirementInfo.setRequirementbackground(requirementinfo.getRequirementbackground());
} if(requirementinfo.getRequirementdescribe() != null) {
resultRequirementInfo.setRequirementdescribe(requirementinfo.getRequirementdescribe());
} if(requirementinfo.getDepartment() != null) {
resultRequirementInfo.setDepartment(requirementinfo.getDepartment());
} if(requirementinfo.getRequirementcontents() != null) {
resultRequirementInfo.setRequirementcontents(requirementinfo.getRequirementcontents());
} if(requirementinfo.getRequirementtype() != -1) {
resultRequirementInfo.setRequirementtype(requirementinfo.getRequirementtype());
}
listResultRequirementInfo.add(resultRequirementInfo);
}
return listResultRequirementInfo;
}
@Override
public List<RequirementInfo> getAllRequirements() {
// 假设LuceneSearchRequirement提供静态访问方法
List<RequirementInfo> listAllrequirement =requirementInfoMapper.RequirementInfoCreateLuceneIndex();
return listAllrequirement;
}
@Override
public void insertNewDepartment(String department) throws Exception{
// TODO Auto-generated method stub
List<String> listdepartment = requirementInfoMapper.selectSeeIfExits(department);
//不存在,插入数据库
if(listdepartment.size() == 0) {
requirementInfoMapper.insertNewDepartment(department);
}
}
}
上面给出的是已有代码,请在此基础上修改,实现将MySQL 中requirement table中requirementtime记录的是需求时间string类型,格式为 YYYY-MM-DD,生成luenceindex检索文档,现在从luenceindex检索大于vue前端传来的日期(string类型)的需求并返回结果列表,请问具体实现代码: