Adding initial working engine.

This commit is contained in:
Sergiotarxz 2023-09-03 21:13:52 +02:00
commit 92c502bc45
3 changed files with 276 additions and 0 deletions

36
pom.xml Normal file
View File

@ -0,0 +1,36 @@
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>info.burguillos</groupId>
<artifactId>search</artifactId>
<version>1</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
<version>9.7.0</version>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-queryparser</artifactId>
<version>9.7.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,12 @@
package info.burguillos.search;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(Application.class, args);
}
}

View File

@ -0,0 +1,228 @@
package info.burguillos.search;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.LinkOption;
import java.nio.file.FileSystems;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.util.FileSystemUtils;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.document.TextField;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Document;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.NIOFSDirectory;
import org.apache.lucene.store.NativeFSLockFactory;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.queryparser.classic.MultiFieldQueryParser;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.queryparser.classic.ParseException;
class ResponseBool {
private boolean ok;
private String reason;
public String getreason() {
return reason;
}
public void setReason(String reason) {
this.reason = reason;
}
public boolean getOk() {
return ok;
}
public void setOk(boolean ok) {
this.ok = ok;
}
}
class SearchObject {
private String title;
private String author;
private String content;
private String url;
private String urlImage;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUrlImage() {
return urlImage;
}
public void setUrlImage(String urlImage) {
this.urlImage = urlImage;
}
}
class ResponseSearch extends ResponseBool {
private List<SearchObject> searchObjects;
public List<SearchObject> getSearchObjects() {
return searchObjects;
}
public void setSearchObjects(List<SearchObject> searchObjects) {
this.searchObjects = searchObjects;
}
}
@RestController
class LoadContentController {
@GetMapping("/")
public ResponseBool root() {
ResponseBool response = new ResponseBool();
response.setOk(true);
return response;
}
private ResponseBool returnFail(String reason) {
ResponseBool response = new ResponseBool();
response.setOk(false);
response.setReason(reason);
return response;
}
@GetMapping(value="/search/{indexName}")
public ResponseBool search(@PathVariable String indexName,
@RequestParam(name = "q") String searchQuery) {
if (indexName == null) {
return returnFail("No queryString.");
}
if (indexName.contains("..") || indexName.contains("/")) {
return returnFail("Invalid indexName.");
}
Path pathIndex = FileSystems.getDefault().getPath("indexes", indexName);
StandardAnalyzer analyzer = new StandardAnalyzer();
if (!Files.exists(pathIndex, LinkOption.NOFOLLOW_LINKS)) {
return returnFail("No such index.");
}
try {
Directory index = new NIOFSDirectory(pathIndex, NativeFSLockFactory.INSTANCE);
Query q = new MultiFieldQueryParser(new String[]{"title", "content"}, analyzer).parse(searchQuery);
IndexReader reader = DirectoryReader.open(index);
IndexSearcher searcher = new IndexSearcher(reader);
TopDocs docs = searcher.search(q, 10);
ScoreDoc[] hits = docs.scoreDocs;
List<SearchObject> searchObjects = new ArrayList<SearchObject>();
for (int i = 0; i < hits.length; ++i) {
int docId = hits[i].doc;
Document d = searcher.doc(docId);
SearchObject searchObject = readDocument(d);
searchObjects.add(searchObject);
}
ResponseSearch responseSearch = new ResponseSearch();
responseSearch.setSearchObjects(searchObjects);
responseSearch.setOk(true);
return responseSearch;
} catch (IOException e) {
e.printStackTrace();
return returnFail("Failed to read index.");
} catch (ParseException e) {
e.printStackTrace();
return returnFail("Unable to understand query.");
}
}
public static SearchObject readDocument(Document d) {
SearchObject searchObject = new SearchObject();
searchObject.setTitle(d.get("title"));
String author = d.get("author");
if (author != null) {
searchObject.setAuthor(author);
}
String content = d.get("content");
if (content.length() > 500) {
content = content.substring(0, 500);
}
searchObject.setContent(content);
searchObject.setUrl(d.get("url"));
String urlImage = d.get("urlImage");
if (urlImage != null) {
searchObject.setUrlImage(urlImage);
}
return searchObject;
}
@PutMapping(value="/index/{indexName}")
public ResponseBool create_index(@PathVariable String indexName, @RequestBody List<SearchObject> searchObjects) {
try {
if (indexName == null) {
return returnFail("No indexName passed.");
}
if (indexName.contains("..") || indexName.contains("/")) {
return returnFail("Invalid indexName.");
}
Path pathIndex = FileSystems.getDefault().getPath("indexes", indexName);
StandardAnalyzer analyzer = new StandardAnalyzer();
if (Files.exists(pathIndex, LinkOption.NOFOLLOW_LINKS)) {
FileSystemUtils.deleteRecursively(pathIndex);
}
Files.createDirectories(pathIndex);
Directory index = new NIOFSDirectory(pathIndex, NativeFSLockFactory.INSTANCE);
IndexWriterConfig config = new IndexWriterConfig(analyzer);
IndexWriter w = new IndexWriter(index, config);
for (SearchObject searchObject : searchObjects) {
addDoc(w, searchObject);
}
w.close();
ResponseBool response = new ResponseBool();
response.setOk(true);
return response;
} catch (Exception e) {
e.printStackTrace();
return returnFail("I/O Error.");
}
}
public static void addDoc(IndexWriter w, SearchObject searchObject) throws IOException {
Document doc = new Document();
doc.add(new TextField("title", searchObject.getTitle(), Field.Store.YES));
if (searchObject.getAuthor() != null) {
doc.add(new TextField("author", searchObject.getAuthor(), Field.Store.YES));
}
doc.add(new TextField("content", searchObject.getContent(), Field.Store.YES));
doc.add(new TextField("url", searchObject.getUrl(), Field.Store.YES));
if (searchObject.getUrlImage() != null) {
doc.add(new TextField("urlImage", searchObject.getUrlImage(), Field.Store.YES));
}
w.addDocument(doc);
}
}