搜索引擎Lucene之皮毛
一、Lucene是apache软件基金会4 jakarta项目组的一个子项目,是一个开放源代码的全文检索引擎工具包,但它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎(英文与德文两种西方语言)。Lucene的目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能,或者是以此为基础建立起完整的全文检索引擎。Lucene是一套用于全文检索和搜寻的开源程式库,由Apache软件基金会支持和提供。Lucene提供了一个简单却强大的应用程式接口,能够做全文索引和搜寻。在Java开发环境里Lucene是一个成熟的免费开源工具。就其本身而言,Lucene是当前以及最近几年最受欢迎的免费Java信息检索程序库。人们经常提到信息检索程序库,虽然与搜索引擎有关,但不应该将信息检索程序库与搜索引擎相混淆。
二、搜索引擎这个东西还是很大的,我这里只是用了一点点皮毛,有兴趣还是去学习一下Solr
三、简易版的搜索实现依赖包
<dependency> <groupId>com.github.magese</groupId> <artifactId>ik-analyzer</artifactId> <version>7.4.0</version> </dependency>
四、代码
import com.alibaba.fastjson.JSONObject; import org.apache.lucene.analysis.TokenStream; import org.apache.lucene.analysis.tokenattributes.CharTermAttribute; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.document.TextField; import org.apache.lucene.index.*; import org.apache.lucene.queryparser.classic.QueryParser; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.store.Directory; import org.apache.lucene.store.RAMDirectory; import org.wltea.analyzer.lucene.IKAnalyzer; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * Funtion: 搜索引擎核心工具类. * <p> * Date: 2018/9/18 14:08 */ public class LuceneUtils { //索引字段 private static final String INDEX_NAME = "searchName"; //用于传输实体类型 public static final String ENTITY_TYPE = "entityType"; //关键词,用于前端 public static final String KEY_WORDS = "keyWords"; private static final Integer VIEW_NUMBER = 100; /** * 搜索引擎,查询结果 * @param searchName * @param objects * @return * @throws Exception */ public static List<JSONObject> search(String searchName, List<Object> objects) throws Exception { //1、准备中文分词器 IKAnalyzer analyzer = new IKAnalyzer(); //2、获取关键词,用于前端使用 List<String> keywords = getKeywords(searchName, analyzer); //3、索引 Directory directory = addIndex(analyzer, objects); //4、查询器 Query query = new QueryParser(INDEX_NAME, analyzer).parse(searchName); //5、搜索 IndexReader reader = DirectoryReader.open(directory); IndexSearcher searcher = new IndexSearcher(reader); ScoreDoc[] scoreDocs = searcher.search(query, VIEW_NUMBER).scoreDocs; //6、查询结果 List<JSONObject> results = getResults(searcher, scoreDocs, keywords); //7、关闭查询 reader.close(); directory.close(); //8、返回结果 return results; } /** * 获取关键词 * @param searchName * @param analyzer * @return * @throws IOException */ private static List<String> getKeywords(String searchName, IKAnalyzer analyzer) throws IOException { List<String> keyWords = new ArrayList<>(); TokenStream tokenStream = analyzer.tokenStream("", searchName); CharTermAttribute attribute = tokenStream.getAttribute(CharTermAttribute.class); tokenStream.reset(); while (tokenStream.incrementToken()) { keyWords.add(attribute.toString()); } tokenStream.close(); return keyWords; } /** * 获取搜索结果 * @param searcher * @param scoreDocs * @return * @throws Exception */ private static List<JSONObject> getResults(IndexSearcher searcher, ScoreDoc[] scoreDocs, List<String> keyWords) throws Exception { if (scoreDocs != null && scoreDocs.length > 0) { IKAnalyzer analyzer = new IKAnalyzer(); List<JSONObject> objects = new ArrayList<>(); //遍历文本 for (ScoreDoc scoreDoc:scoreDocs) { Document document = searcher.doc(scoreDoc.doc); List<IndexableField> fields = document.getFields(); if (fields != null && !fields.isEmpty()) { //获取指定索引数据 JSONObject jsonObject = JSONObject.parseObject(document.get(INDEX_NAME)); jsonObject.put(ENTITY_TYPE, document.get(ENTITY_TYPE)); jsonObject.put(KEY_WORDS, keyWords); objects.add(jsonObject); } } return objects; } return null; } /** * 添加索引 * @param analyzer * @param objects * @return * @throws IOException */ private static Directory addIndex(IKAnalyzer analyzer, List<Object> objects) throws IOException { //使用内存方式 Directory directory = new RAMDirectory(); IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer); IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig); if (objects != null && !objects.isEmpty()) { //添加索引 for (Object object:objects) { Document document = new Document(); document.add(new TextField(INDEX_NAME, JSONObject.toJSONString(object), Field.Store.YES)); document.add(new TextField(ENTITY_TYPE, object.getClass().getName(), Field.Store.YES)); indexWriter.addDocument(document); } } indexWriter.close(); return directory; } }