不使用ElasticSearch,怎么做一个轻量级的全文搜索(文本匹配)?
| Java
评论 0 | 点赞 0 | 浏览 956

前言

提起全文搜索,程序员往往首先想到ElasticSearch,ElasticSearch确实是目前最热门的全文搜索引擎了。

但是ElasticSearch太重量级了,如果你维护的只是一个小项目,数据量很微小(例如个人博客),或者只是某个小场景中需要用到文本相似度匹配,那么因为这么个小功能而去选择接入ElasticSearch,这好比用大炮打蚊子,大材小用,还会额外增加系统的复杂度及运维成本。

这里我介绍一种非常轻量级的方案供参考,该方案不需要接入任何外部系统,非常适合数据量小的场景。如果你是数据量大的场景,还是推荐上ElasticSearch。

ElasticSearch的底层是基于Lucene的,通常情况下,使用Lucene需要建立基于物理存储路径的索引,但是Lucene还提供了基于内存的RAMDirectory索引,使用内存索引,你可以将数据加载到内存中,并在内存中进行搜索和匹配操作,不需要将数据持久化到磁盘上。

使用方法

首先引入相关的maven依赖,这里的版本我强烈建议用低版本4.10.2,我曾拿4.x版本对比过8.x版本,结果是前者明显优于后者,原因不清楚。

  <properties>
        <lunece.version>4.10.2</lunece.version>
    </properties>
    <!-- lucene核心库 -->
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-core</artifactId>
            <version>${lunece.version}</version>
        </dependency>
        <!-- Lucene的查询解析器 -->
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-queryparser</artifactId>
            <version>${lunece.version}</version>
        </dependency>
        <!-- lucene的默认分词器库 -->
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-analyzers-common</artifactId>
            <version>${lunece.version}</version>
        </dependency>

下面是demo

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryparser.classic.ParseException;
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.search.TopDocs;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.Version;
public class LuceneRAMDirectoryExample {
    public static void main(String[] args) {
        try {
            // 创建内存索引目录
            RAMDirectory ramDirectory = new RAMDirectory();
            // 创建分析器
            Analyzer analyzer = new StandardAnalyzer();
            // 创建索引写入器配置
            IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LATEST, analyzer);
            // 创建索引写入器
            IndexWriter indexWriter = new IndexWriter(ramDirectory, indexWriterConfig);
            // 创建文档并添加到索引中
            Document doc1 = new Document();
            doc1.add(new TextField("content", "This is the first document", Field.Store.YES));
            indexWriter.addDocument(doc1);
            Document doc2 = new Document();
            doc2.add(new TextField("content", "This is the second document", Field.Store.YES));
            indexWriter.addDocument(doc2);
            // 提交索引并关闭写入器
            indexWriter.commit();
            indexWriter.close();
            // 创建索引搜索器
            DirectoryReader directoryReader = DirectoryReader.open(ramDirectory);
            IndexSearcher indexSearcher = new IndexSearcher(directoryReader);
            // 创建查询解析器
            QueryParser queryParser = new QueryParser("content", analyzer);
            // 创建查询
            Query query = queryParser.parse("first");
            // 执行搜索
            TopDocs topDocs = indexSearcher.search(query, 10);
            // 遍历搜索结果
            for (ScoreDoc scoreDoc : topDocs.scoreDocs) {
                Document document = indexSearcher.doc(scoreDoc.doc);
                System.out.println("Score: " + scoreDoc.score);
                System.out.println("Content: " + document.get("content"));
            }
            // 关闭索引搜索器和内存索引目录
            directoryReader.close();
            ramDirectory.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

上面的demo中,索引中存在两个文档,

文档一:This is the first document
文档二:This is the second document

搜索关键词为“first”,程序输出结果如下:

Score: 0.625
Content: This is the first document

Lucene会对每个文档基于匹配度进行打分,得分越高,匹配度越高。在实际业务中,可以根据匹配度排序,筛选出前N条作为搜索结果;也可以再进一步优化,按照重要程度给不同的文档做不同的权重,计算加权之后的匹配度。

本文作者:不是好驴
本文链接:https://www.baddonkey.cn/detail/47
版权声明:原创文章,允许转载,转载请注明出处

高谈阔论

留言列表