全文检索
数据分类
- 结构化数据
 - 非结构化数据
 
数据查询
结构化查询
非结构化查询
- 顺序扫描法
 - 全文检索
 
索引
倒排索引:根据词找文章
| DocId | Doc | 
|---|---|
| 1 | 谷歌地图之父跳槽 Facebook | 
| 2 | 谷歌地图之父加盟 Facebook | 
| 3 | 谷歌地图创始人拉斯离开谷歌加盟 Facebook | 
| 4 | 谷歌地图之父跳槽 Facebook 与 Wave 项目取消有关 | 
| 5 | 谷歌地图之父拉斯加盟社交网站 Facebook | 
对这些doc进行分词之后,以词为主键,记录哪些doc出现了这些词
| WordId | Word | DocIds | 
|---|---|---|
| 1 | 谷歌 | 1,2,3,4,5 | 
| 2 | 地图 | 1,2,3,4,5 | 
| 3 | 之父 | 1,2,4,5 | 
| 4 | 跳槽 | 1,4 | 
| 5 | 1,2,3,4,5 | |
| 6 | 加盟 | 2,3,5 | 
| 7 | 创始人 | 3 | 
| 8 | 拉斯 | 3,5 | 
| 9 | 离开 | 3 | 
| 10 | 与 | 4 | 
| .. | .. | .. | 
正排索引:根据文章找词
应用场景
- 数据量大
 - 数据结构不固定
 
技术选型
目前开源可用的全文检索中间件只有ElasticSearch与Solr 二者都是基于Lucene
ES在许多方面都超过了Solr 所以目前只能选择ES
Lucene

创建索引库
// 创建directory指定索引存放位置
Directory directory = FSDirectory.open(new File("./index").toPath());
IndexWriter indexWriter = new IndexWriter(directory,new IndexWriterConfig());
File dir = new File("./res");
File[] files = dir.listFiles();
assert files != null;
// 遍历文件
for (File file : files) {
    String fileName = file.getName();
    String filePath = file.getPath();
    String content = FileUtils.readFileToString(file, "utf8");
    long fileSize = FileUtils.sizeOf(file);
            
    // 根据文件内容生成成员
    Field fieldName = new TextField("name",fileName, Field.Store.YES);
    Field fieldPath = new TextField("path",filePath,Field.Store.YES);
    Field fieldContent = new TextField("content",content,Field.Store.YES);
    Field fieldSize = new TextField("size", String.valueOf(fileSize),Field.Store.YES);
    // 将成员添加到文档中
    Document document = new Document();
    document.add(fieldName);
    document.add(fieldPath);
    document.add(fieldContent);
    document.add(fieldSize);
    // 将文档写入索引库
    indexWriter.addDocument(document);
}
indexWriter.close();
搜索
// 创建directory指定索引存放位置
Directory directory = FSDirectory.open(new File("./index").toPath());
IndexReader indexReader = DirectoryReader.open(directory);
IndexSearcher indexSearcher = new IndexSearcher(indexReader);
Query query = new TermQuery(new Term("content","spring"));
TopDocs docs = indexSearcher.search(query, 10);
System.out.println("总记录数:"+docs.totalHits);
ScoreDoc[] scoreDocs = docs.scoreDocs;
for (ScoreDoc scoreDoc : scoreDocs) {
    int id = scoreDoc.doc;
    Document document = indexSearcher.doc(id);
    System.out.println(document.get("name"));
    System.out.println(document.get("path"));
    System.out.println(document.get("size"));
//            System.out.println(document.get("content"));
    System.out.println("--------------");
}
indexReader.close();
分析
Analyzer analyzer = new StandardAnalyzer();
TokenStream tokenStream = analyzer.tokenStream("", "Learn how to create a web page with Spring MVC.");
CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class);
tokenStream.reset();
while (tokenStream.incrementToken()){
    System.out.println(charTermAttribute.toString());
}
使用别的分析器
Analyzer analyzer = new IKAnalyzer();
维护

删除
        Directory directory = FSDirectory.open(new File("./index").toPath());
        IndexWriter indexWriter = new IndexWriter(directory,new IndexWriterConfig());
        //indexWriter.deleteAll();
        indexWriter.deleteDocuments(new Term("content","name"));
        indexWriter.close();
更新
indexWriter.updateDocument(new Term("content","name"),document);