spring boot +vue+lucene+tika实现一个类似于百度文库的文件检索功能
需求分析
根据需求,我们需要实现一个类似于百度文库的文件检索功能。以下是功能的分解:
-
需求分析:
- 用户上传文件(如PDF、Word、Excel等)。
- 系统对文件内容进行索引(使用Lucene)。
- 用户可以通过关键词搜索文件内容。
- 搜索结果展示文件名、摘要信息以及匹配度。
-
项目构建:
- 后端使用Spring Boot作为框架,集成Lucene进行全文索引和搜索。
- 使用Apache Tika解析不同类型的文件内容。
- 前端使用Vue.js实现用户界面,包括文件上传、搜索框和结果展示。
-
代码边界:
- 后端负责文件解析、索引构建和搜索逻辑。
- 前端负责用户交互和结果显示。
-
结果展示:
- 搜索结果显示文件名、摘要信息以及匹配度。
- 支持分页显示搜索结果。
项目结构
shop-api/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/example/shop/
│ │ │ ├── controller/
│ │ │ │ └── FileSearchController.java
│ │ │ ├── service/
│ │ │ │ ├── FileService.java
│ │ │ │ └── SearchService.java
│ │ │ ├── model/
│ │ │ │ └── SearchResult.java
│ │ │ └── config/
│ │ │ └── LuceneConfig.java
│ │ └── resources/
│ │ └── application.properties
└── pom.xml
后端代码实现
1. Lucene配置类
package com.example.shop.config;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.nio.file.Paths;
@Configuration
public class LuceneConfig {
private static final String INDEX_DIR = "lucene-index";
@Bean
public Directory directory() throws Exception {
return FSDirectory.open(Paths.get(INDEX_DIR));
}
@Bean
public IndexWriter indexWriter(Directory directory) throws Exception {
IndexWriterConfig config = new IndexWriterConfig(new StandardAnalyzer());
return new IndexWriter(directory, config);
}
@Bean
public DirectoryReader directoryReader(Directory directory) throws Exception {
return DirectoryReader.open(directory);
}
}
2. 文件服务类
package com.example.shop.service;
import org.apache.tika.Tika;
import org.apache.tika.exception.TikaException;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.xml.sax.SAXException;
import java.io.IOException;
@Service
public class FileService {
private final Tika tika = new Tika();
/**
* 解析文件内容
* @param file 上传的文件
* @return 文件内容
*/
public String parseFile(MultipartFile file) throws IOException, TikaException, SAXException {
return tika.parseToString(file.getInputStream());
}
}
3. 搜索服务类
package com.example.shop.service;
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.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.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@Service
public class SearchService {
@Autowired
private IndexWriter indexWriter;
@Autowired
private DirectoryReader directoryReader;
/**
* 添加文件到索引
* @param fileName 文件名
* @param content 文件内容
*/
public void addFileToIndex(String fileName, String content) throws IOException {
Document doc = new Document();
doc.add(new TextField("fileName", fileName, Field.Store.YES));
doc.add(new TextField("content", content, Field.Store.YES));
indexWriter.addDocument(doc);
indexWriter.commit();
}
/**
* 搜索文件
* @param keyword 关键词
* @return 搜索结果列表
*/
public List<SearchResult> searchFiles(String keyword) throws IOException, ParseException {
List<SearchResult> results = new ArrayList<>();
IndexSearcher searcher = new IndexSearcher(directoryReader);
Query query = new QueryParser("content", new StandardAnalyzer()).parse(keyword);
TopDocs topDocs = searcher.search(query, 10);
for (ScoreDoc scoreDoc : topDocs.scoreDocs) {
Document doc = searcher.doc(scoreDoc.doc);
SearchResult result = new SearchResult();
result.setFileName(doc.get("fileName"));
result.setContent(doc.get("content").substring(0, Math.min(100, doc.get("content").length())));
result.setScore(scoreDoc.score);
results.add(result);
}
return results;
}
}
4. 搜索结果模型
package com.example.shop.model;
public class SearchResult {
private String fileName;
private String content;
private float score;
// Getters and Setters
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public float getScore() {
return score;
}
public void setScore(float score) {
this.score = score;
}
}
5. 控制器类
package com.example.shop.controller;
import com.example.shop.model.SearchResult;
import com.example.shop.service.FileService;
import com.example.shop.service.SearchService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.List;
@RestController
@RequestMapping("/api/file")
public class FileSearchController {
@Autowired
private FileService fileService;
@Autowired
private SearchService searchService;
/**
* 上传文件并添加到索引
*/
@PostMapping("/upload")
public String uploadFile(@RequestParam("file") MultipartFile file) {
try {
String content = fileService.parseFile(file);
searchService.addFileToIndex(file.getOriginalFilename(), content);
return "File uploaded and indexed successfully.";
} catch (Exception e) {
return "Error uploading file: " + e.getMessage();
}
}
/**
* 搜索文件
*/
@GetMapping("/search")
public List<SearchResult> searchFiles(@RequestParam("keyword") String keyword) {
try {
return searchService.searchFiles(keyword);
} catch (Exception e) {
throw new RuntimeException("Error searching files: " + e.getMessage());
}
}
}
前端代码实现
前端使用Vue.js实现,以下是关键部分:
1. 主页面
<template>
<div id="app">
<h1>文件检索系统</h1>
<input type="file" @change="uploadFile" />
<input type="text" v-model="keyword" placeholder="请输入关键词" />
<button @click="searchFiles">搜索</button>
<ul>
<li v-for="result in searchResults" :key="result.fileName">
<strong>{{ result.fileName }}</strong>
<p>{{ result.content }}</p>
<span>匹配度: {{ result.score.toFixed(2) }}</span>
</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
keyword: "",
searchResults: []
};
},
methods: {
uploadFile(event) {
const file = event.target.files[0];
const formData = new FormData();
formData.append("file", file);
fetch("/api/file/upload", {
method: "POST",
body: formData
}).then(response => response.text()).then(data => alert(data));
},
searchFiles() {
fetch(`/api/file/search?keyword=${this.keyword}`)
.then(response => response.json())
.then(data => (this.searchResults = data));
}
}
};
</script>
总结
功能模块 | 描述 |
---|---|
文件上传 | 用户上传文件,后端解析文件内容并添加到Lucene索引。 |
文件搜索 | 用户输入关键词,后端返回匹配的文件列表,包含文件名、摘要和匹配度。 |
前端界面 | 使用Vue.js实现文件上传和搜索结果展示。 |
技术栈 | Spring Boot + Lucene + Tika + Vue.js |
以上代码实现了文件检索的核心功能,可以根据需求进一步优化和扩展。