新增pdf/doc/markdown解析
This commit is contained in:
parent
16a6eeab86
commit
22426a30d9
36
pom.xml
36
pom.xml
@ -35,6 +35,11 @@
|
|||||||
<guava.version>31.0.1-jre</guava.version>
|
<guava.version>31.0.1-jre</guava.version>
|
||||||
|
|
||||||
<elasticsearch-rest-high-level-client.version>7.17.10</elasticsearch-rest-high-level-client.version>
|
<elasticsearch-rest-high-level-client.version>7.17.10</elasticsearch-rest-high-level-client.version>
|
||||||
|
|
||||||
|
<pdfbox.version>2.0.29</pdfbox.version>
|
||||||
|
<poi.version>5.2.3</poi.version>
|
||||||
|
<poi-ooxml.version>5.2.3</poi-ooxml.version>
|
||||||
|
|
||||||
</properties>
|
</properties>
|
||||||
<dependencyManagement>
|
<dependencyManagement>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@ -159,6 +164,24 @@
|
|||||||
<version>${elasticsearch-rest-high-level-client.version}</version>
|
<version>${elasticsearch-rest-high-level-client.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- pdf/word的解析 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.pdfbox</groupId>
|
||||||
|
<artifactId>pdfbox</artifactId>
|
||||||
|
<version>${pdfbox.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.poi</groupId>
|
||||||
|
<artifactId>poi</artifactId>
|
||||||
|
<version>${poi.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.poi</groupId>
|
||||||
|
<artifactId>poi-ooxml</artifactId>
|
||||||
|
<version>${poi-ooxml.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</dependencyManagement>
|
</dependencyManagement>
|
||||||
|
|
||||||
@ -267,6 +290,19 @@
|
|||||||
<artifactId>elasticsearch-rest-high-level-client</artifactId>
|
<artifactId>elasticsearch-rest-high-level-client</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.pdfbox</groupId>
|
||||||
|
<artifactId>pdfbox</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.poi</groupId>
|
||||||
|
<artifactId>poi</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.poi</groupId>
|
||||||
|
<artifactId>poi-ooxml</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
24
src/main/java/com/doc/parser/domain/enums/DocTypeEnum.java
Normal file
24
src/main/java/com/doc/parser/domain/enums/DocTypeEnum.java
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package com.doc.parser.domain.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Luke.ye
|
||||||
|
* @date 2025/5/20 09:03
|
||||||
|
*/
|
||||||
|
public enum DocTypeEnum {
|
||||||
|
|
||||||
|
MARKDOWN("markdown", "markdown"),
|
||||||
|
HTML("html", "html"),
|
||||||
|
PDF("pdf", "pdf"),
|
||||||
|
WORD("word", "word"),
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
public String code;
|
||||||
|
|
||||||
|
public String desc;
|
||||||
|
|
||||||
|
DocTypeEnum(String code, String desc) {
|
||||||
|
this.code = code;
|
||||||
|
this.desc = desc;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
package com.doc.parser.domain.iface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Luke.ye
|
||||||
|
* @date 2025/5/20 09:02
|
||||||
|
*/
|
||||||
|
public interface DocumentImporter {
|
||||||
|
void importDocuments() throws Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link com.doc.parser.domain.enums.DocTypeEnum}
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
String getType();
|
||||||
|
}
|
||||||
@ -0,0 +1,61 @@
|
|||||||
|
package com.doc.parser.domain.impl;
|
||||||
|
|
||||||
|
import com.doc.parser.domain.enums.DocTypeEnum;
|
||||||
|
import com.doc.parser.domain.iface.DocumentImporter;
|
||||||
|
import org.elasticsearch.action.index.IndexRequest;
|
||||||
|
import org.elasticsearch.client.RequestOptions;
|
||||||
|
import org.elasticsearch.client.RestHighLevelClient;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.*;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Luke.ye
|
||||||
|
* @date 2025/5/20 09:06
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class MarkdownImporter implements DocumentImporter {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(MarkdownImporter.class);
|
||||||
|
private static final String INDEX_NAME = "documents";
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RestHighLevelClient esClient;
|
||||||
|
|
||||||
|
@Value("${markdown.path}")
|
||||||
|
private String directoryPath;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void importDocuments() throws IOException {
|
||||||
|
Files.walk(Paths.get(directoryPath))
|
||||||
|
.filter(p -> p.toString().toLowerCase().endsWith(".md"))
|
||||||
|
.forEach(path -> {
|
||||||
|
try {
|
||||||
|
String content = Files.readString(path);
|
||||||
|
Map<String, Object> doc = new HashMap<>();
|
||||||
|
doc.put("filename", path.getFileName().toString());
|
||||||
|
doc.put("filepath", path.toAbsolutePath().toString());
|
||||||
|
doc.put("content", content);
|
||||||
|
|
||||||
|
IndexRequest request = new IndexRequest(INDEX_NAME).source(doc);
|
||||||
|
esClient.index(request, RequestOptions.DEFAULT);
|
||||||
|
|
||||||
|
logger.info("导入成功: {}", path.getFileName());
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("导入失败: {}", path, e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return DocTypeEnum.MARKDOWN.code;
|
||||||
|
}
|
||||||
|
}
|
||||||
61
src/main/java/com/doc/parser/domain/impl/PdfImporter.java
Normal file
61
src/main/java/com/doc/parser/domain/impl/PdfImporter.java
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
package com.doc.parser.domain.impl;
|
||||||
|
|
||||||
|
import com.doc.parser.domain.enums.DocTypeEnum;
|
||||||
|
import com.doc.parser.domain.iface.DocumentImporter;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
|
import org.apache.pdfbox.text.PDFTextStripper;
|
||||||
|
import org.elasticsearch.action.index.IndexRequest;
|
||||||
|
import org.elasticsearch.client.RequestOptions;
|
||||||
|
import org.elasticsearch.client.RestHighLevelClient;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.nio.file.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Luke.ye
|
||||||
|
* @date 2025/5/20 10:23
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class PdfImporter implements DocumentImporter {
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(PdfImporter.class);
|
||||||
|
private final RestHighLevelClient esClient;
|
||||||
|
|
||||||
|
@Value("${pdf.path}")
|
||||||
|
private String directoryPath;
|
||||||
|
|
||||||
|
public PdfImporter(RestHighLevelClient esClient) {
|
||||||
|
this.esClient = esClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void importDocuments() throws Exception {
|
||||||
|
Files.walk(Paths.get(directoryPath))
|
||||||
|
.filter(p -> p.toString().toLowerCase().endsWith(".pdf"))
|
||||||
|
.forEach(path -> {
|
||||||
|
try (PDDocument document = PDDocument.load(new File(path.toString()))) {
|
||||||
|
String content = new PDFTextStripper().getText(document);
|
||||||
|
Map<String, Object> doc = new HashMap<>();
|
||||||
|
doc.put("filename", path.getFileName().toString());
|
||||||
|
doc.put("filepath", path.toAbsolutePath().toString());
|
||||||
|
doc.put("content", content);
|
||||||
|
|
||||||
|
IndexRequest request = new IndexRequest("documents").source(doc);
|
||||||
|
esClient.index(request, RequestOptions.DEFAULT);
|
||||||
|
LOGGER.info("导入成功: {}", path.getFileName());
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOGGER.error("导入失败: {}", path, e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return DocTypeEnum.PDF.code;
|
||||||
|
}
|
||||||
|
}
|
||||||
65
src/main/java/com/doc/parser/domain/impl/WordImporter.java
Normal file
65
src/main/java/com/doc/parser/domain/impl/WordImporter.java
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
package com.doc.parser.domain.impl;
|
||||||
|
|
||||||
|
import com.doc.parser.domain.enums.DocTypeEnum;
|
||||||
|
import com.doc.parser.domain.iface.DocumentImporter;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.apache.poi.xwpf.usermodel.XWPFDocument;
|
||||||
|
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
|
||||||
|
import org.elasticsearch.action.index.IndexRequest;
|
||||||
|
import org.elasticsearch.client.RequestOptions;
|
||||||
|
import org.elasticsearch.client.RestHighLevelClient;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.nio.file.*;
|
||||||
|
import java.util.*;
|
||||||
|
/**
|
||||||
|
* @author Luke.ye
|
||||||
|
* @date 2025/5/20 10:25
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class WordImporter implements DocumentImporter {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(WordImporter.class);
|
||||||
|
|
||||||
|
private final RestHighLevelClient esClient;
|
||||||
|
|
||||||
|
@Value("${word.path}")
|
||||||
|
private String directoryPath;
|
||||||
|
|
||||||
|
public WordImporter(RestHighLevelClient esClient) {
|
||||||
|
this.esClient = esClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void importDocuments() throws Exception {
|
||||||
|
Files.walk(Paths.get(directoryPath))
|
||||||
|
.filter(p -> p.toString().toLowerCase().endsWith(".docx"))
|
||||||
|
.forEach(path -> {
|
||||||
|
try (XWPFDocument docx = new XWPFDocument(new FileInputStream(path.toFile()))) {
|
||||||
|
StringBuilder content = new StringBuilder();
|
||||||
|
for (XWPFParagraph para : docx.getParagraphs()) {
|
||||||
|
content.append(para.getText()).append("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Object> doc = new HashMap<>();
|
||||||
|
doc.put("filename", path.getFileName().toString());
|
||||||
|
doc.put("filepath", path.toAbsolutePath().toString());
|
||||||
|
doc.put("content", content.toString());
|
||||||
|
|
||||||
|
IndexRequest request = new IndexRequest("documents").source(doc);
|
||||||
|
esClient.index(request, RequestOptions.DEFAULT);
|
||||||
|
LOGGER.info("导入成功: {}", path.getFileName());
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOGGER.error("导入失败: {}", path, e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return DocTypeEnum.WORD.code;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
package com.doc.parser.infrastructure.north.controller;
|
||||||
|
|
||||||
|
import com.doc.parser.domain.iface.DocumentImporter;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/import")
|
||||||
|
public class ImportController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private List<DocumentImporter> importers;
|
||||||
|
|
||||||
|
@GetMapping("/{type}")
|
||||||
|
public ResponseEntity<String> importByType(@PathVariable String type) {
|
||||||
|
for (DocumentImporter importer : importers) {
|
||||||
|
if (importer.getType().equalsIgnoreCase(type)) {
|
||||||
|
try {
|
||||||
|
importer.importDocuments();
|
||||||
|
return ResponseEntity.ok(type + " 文件导入成功");
|
||||||
|
} catch (Exception e) {
|
||||||
|
return ResponseEntity.internalServerError().body("导入失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ResponseEntity.badRequest().body("不支持的类型: " + type);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,61 @@
|
|||||||
|
package com.doc.parser.infrastructure.north.controller;
|
||||||
|
|
||||||
|
|
||||||
|
import org.elasticsearch.action.search.SearchRequest;
|
||||||
|
import org.elasticsearch.action.search.SearchResponse;
|
||||||
|
import org.elasticsearch.client.*;
|
||||||
|
import org.elasticsearch.index.query.QueryBuilders;
|
||||||
|
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||||
|
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
|
||||||
|
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
|
||||||
|
import org.elasticsearch.search.SearchHit;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Luke.ye
|
||||||
|
* @date 2025/5/20 16:56
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/search")
|
||||||
|
public class SearchController {
|
||||||
|
|
||||||
|
private final RestHighLevelClient esClient;
|
||||||
|
|
||||||
|
public SearchController(RestHighLevelClient esClient) {
|
||||||
|
this.esClient = esClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public List<Map<String, Object>> search(@RequestParam String q) throws Exception {
|
||||||
|
SearchRequest request = new SearchRequest("documents");
|
||||||
|
|
||||||
|
HighlightBuilder highlight = new HighlightBuilder()
|
||||||
|
.field("content")
|
||||||
|
.preTags("<mark>")
|
||||||
|
.postTags("</mark>")
|
||||||
|
.fragmentSize(80)
|
||||||
|
.numOfFragments(3);
|
||||||
|
|
||||||
|
SearchSourceBuilder builder = new SearchSourceBuilder()
|
||||||
|
.query(QueryBuilders.matchQuery("content", q))
|
||||||
|
.highlighter(highlight)
|
||||||
|
.size(10);
|
||||||
|
|
||||||
|
request.source(builder);
|
||||||
|
SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);
|
||||||
|
|
||||||
|
List<Map<String, Object>> results = new ArrayList<>();
|
||||||
|
for (SearchHit hit : response.getHits()) {
|
||||||
|
Map<String, Object> source = hit.getSourceAsMap();
|
||||||
|
Map<String, Object> result = new HashMap<>();
|
||||||
|
result.put("filename", source.get("filename"));
|
||||||
|
result.put("filepath", source.get("filepath"));
|
||||||
|
result.put("highlight", hit.getHighlightFields().getOrDefault("content", null));
|
||||||
|
results.add(result);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -13,10 +13,12 @@ logging.org.springframework.context=${logging.level.com.doc.parser}
|
|||||||
|
|
||||||
|
|
||||||
# ES相关
|
# ES相关
|
||||||
elasticsearch.host=localhost
|
elasticsearch.host=es.wisdompulse.cn
|
||||||
elasticsearch.port=9200
|
elasticsearch.port=80
|
||||||
elasticsearch.scheme=http
|
elasticsearch.scheme=http
|
||||||
|
|
||||||
|
|
||||||
# 导入的材料路径
|
# 导入的材料路径
|
||||||
markdown.path = D:/02-documents/01-ahnx-share-src-public/public/设计模式
|
markdown.path=/Users/admin/Desktop/ahnx-share-src-public
|
||||||
|
pdf.path=/Users/admin/Desktop/ahnx-share-src-public
|
||||||
|
word.path=/Users/admin/Desktop/ahnx-share-src-public
|
||||||
Loading…
x
Reference in New Issue
Block a user