init
This commit is contained in:
213
search-engine/SearchClient.java
Normal file
213
search-engine/SearchClient.java
Normal file
@@ -0,0 +1,213 @@
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
// Name: Niklas Johnson
|
||||
// Date: 4-2-2024
|
||||
|
||||
// This class allows users to find and rate books within BOOK_DIRECTORY
|
||||
// containing certain terms. Also handles omitting items if the query is prefixed
|
||||
// with a '-'
|
||||
public class SearchClient {
|
||||
public static final String BOOK_DIRECTORY = "./books";
|
||||
|
||||
public static void main(String[] args) throws FileNotFoundException {
|
||||
Scanner console = new Scanner(System.in);
|
||||
List<Book> books = loadBooks();
|
||||
List<Media> media = new ArrayList<>(books);
|
||||
|
||||
Map<String, Set<Media>> index = createIndex(media);
|
||||
|
||||
System.out.println("Welcome to the CSE 123 Search Engine!");
|
||||
String command = "";
|
||||
while (!command.equalsIgnoreCase("quit")) {
|
||||
System.out.println("What would you like to do? [Search, Rate, Quit]");
|
||||
System.out.print("> ");
|
||||
command = console.nextLine();
|
||||
|
||||
if (command.equalsIgnoreCase("search")) {
|
||||
searchQuery(console, index);
|
||||
} else if (command.equalsIgnoreCase("rate")) {
|
||||
addRating(console, media);
|
||||
} else if (!command.equalsIgnoreCase("quit")) {
|
||||
System.out.println("Invalid command, please try again.");
|
||||
}
|
||||
}
|
||||
System.out.println("See you next time!");
|
||||
}
|
||||
|
||||
// Produces and returns a "deep copy" of the parameter map, which has the same
|
||||
// structure and values as the parameter, but with all internal data structures
|
||||
// and values copied. After calling this method, modifying the parameter or
|
||||
// return value should NOT affect the other.
|
||||
//
|
||||
// Parameters:
|
||||
// inputMap - the map to duplicate
|
||||
//
|
||||
// Returns:
|
||||
// A deep copy of the parameter map.
|
||||
// TODO: Copy fixed version and update to use Media
|
||||
public static Map<String, Set<Media>> deepCopy(Map<String, Set<Media>> inputMap) {
|
||||
Map<String, Set<Media>> deepCopy = new TreeMap<>();
|
||||
|
||||
for (String key : inputMap.keySet()) {
|
||||
Set<Media> inputSet = new HashSet<>(inputMap.get(key));
|
||||
deepCopy.put(key, inputSet);
|
||||
}
|
||||
return deepCopy;
|
||||
}
|
||||
// creates a directory of words that appear in a given list of Strings
|
||||
// takes a list of strings to process
|
||||
// returns sorted map containing the index
|
||||
// no thrown exceptions
|
||||
public static Map<String, Set<Media>> createIndex(List<Media> media) throws FileNotFoundException {
|
||||
Map<String, Set<Media>> index = new TreeMap<>();
|
||||
Set<String> uniqueWords = getUniqueWords(media);
|
||||
|
||||
for (String uniqueWord : uniqueWords) {
|
||||
index.put(uniqueWord.toLowerCase(), new HashSet<Media>());
|
||||
}
|
||||
|
||||
for (String word : index.keySet()) {
|
||||
for (int i = 0; i < media.size(); i++) {
|
||||
Scanner titleScanner = new Scanner(media.get(i).getTitle());
|
||||
while (titleScanner.hasNext()) {
|
||||
if (titleScanner.next().equalsIgnoreCase(word)) {
|
||||
index.get(word).add(media.get(i));
|
||||
}
|
||||
}
|
||||
titleScanner.close();
|
||||
|
||||
for (String artists : media.get(i).getArtists()) {
|
||||
Scanner artistScanner = new Scanner(artists);
|
||||
while (artistScanner.hasNext()) {
|
||||
if (artistScanner.next().equalsIgnoreCase(word)) {
|
||||
index.get(word).add(media.get(i));
|
||||
}
|
||||
}
|
||||
artistScanner.close();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
// helper method for createIndex. looks through given list of strings,
|
||||
// keeping track of only unique words
|
||||
// takes list of words to prune
|
||||
// returns pruned set of words
|
||||
// no thrown exceptions
|
||||
public static Set<String> getUniqueWords(List<Media> media) throws FileNotFoundException {
|
||||
Set<String> uniqueWords = new HashSet<>();
|
||||
for (Media thing : media) {
|
||||
Scanner mediaScanner = new Scanner(new File(BOOK_DIRECTORY + "/" + thing.getTitle() + ".txt"));
|
||||
while (mediaScanner.hasNext()) {
|
||||
uniqueWords.add(mediaScanner.next());
|
||||
}
|
||||
mediaScanner.close();
|
||||
}
|
||||
return uniqueWords;
|
||||
}
|
||||
|
||||
// Allows the user to search a specific query using the provided 'index' to find appropraite
|
||||
// Media entries.
|
||||
//
|
||||
// Parameters:
|
||||
// console - the Scanner to get user input from
|
||||
// index - invertedIndex mapping terms to the Set of media containing those terms
|
||||
public static void searchQuery(Scanner console, Map<String, Set<Media>> index) {
|
||||
System.out.println("Enter query:");
|
||||
System.out.print("> ");
|
||||
String query = console.nextLine();
|
||||
Optional<Set<Media>> result = search(deepCopy(index), query);
|
||||
|
||||
if (result.isEmpty()) {
|
||||
System.out.println("\tNo results!");
|
||||
} else {
|
||||
for (Media m : result.get()) {
|
||||
System.out.println("\t" + m.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Allows the user to add a rating to one of the options wthin 'media'
|
||||
//
|
||||
// Parameters:
|
||||
// console - the Scanner to get user input from
|
||||
// media - list of all media options loaded into the search engine
|
||||
public static void addRating(Scanner console, List<Media> media) {
|
||||
System.out.print("[" + media.get(0).getTitle());
|
||||
for (int i = 1; i < media.size(); i++) {
|
||||
System.out.print(", " + media.get(i).getTitle());
|
||||
}
|
||||
System.out.println("]");
|
||||
System.out.println("What would you like to rate (enter index)?");
|
||||
System.out.print("> ");
|
||||
int choice = Integer.parseInt(console.nextLine());
|
||||
if (choice < 0 || choice >= media.size()) {
|
||||
System.out.println("Invalid choice");
|
||||
} else {
|
||||
System.out.println("Rating [" + media.get(choice).getTitle() + "]");
|
||||
System.out.println("What rating would you give?");
|
||||
System.out.print("> ");
|
||||
int rating = Integer.parseInt(console.nextLine());
|
||||
media.get(choice).addRating(rating);
|
||||
}
|
||||
}
|
||||
|
||||
// Searches a specific query using the provided 'index' to find appropraite Media entries.
|
||||
// terms are determined by whitespace separation. If a term is proceeded by '-' any entry
|
||||
// containing that term will be removed from the result.
|
||||
//
|
||||
// Parameters:
|
||||
// index - invertedIndex mapping terms to the Set of media containing those terms
|
||||
// query - user's entered query string to use in searching
|
||||
//
|
||||
// Returns:
|
||||
// An optional set of all Media containing the requirested terms. If none, Optional.Empty()
|
||||
public static Optional<Set<Media>> search(Map<String, Set<Media>> index, String query) {
|
||||
Optional<Set<Media>> ret = Optional.empty();
|
||||
|
||||
Scanner tokens = new Scanner(query);
|
||||
while (tokens.hasNext()) {
|
||||
boolean minus = false;
|
||||
String token = tokens.next().toLowerCase();
|
||||
if (token.startsWith("-")) {
|
||||
minus = true;
|
||||
token = token.substring(1);
|
||||
}
|
||||
|
||||
if (index.containsKey(token)) {
|
||||
if (ret.isEmpty() && !minus) {
|
||||
ret = Optional.of(index.get(token));
|
||||
} else if (!ret.isEmpty() && minus) {
|
||||
ret.get().removeAll(index.get(token));
|
||||
} else if (!ret.isEmpty() && !minus) {
|
||||
ret.get().retainAll(index.get(token));
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Loads all books from BOOK_DIRECTORY. Assumes that each book starts with two lines -
|
||||
// "Title: " which is followed by the book's title
|
||||
// "Author: " which is followed by the book's author
|
||||
//
|
||||
// Returns:
|
||||
// A list of all book objects corresponding to the ones located in BOOK_DIRECTORY
|
||||
public static List<Book> loadBooks() throws FileNotFoundException {
|
||||
List<Book> ret = new ArrayList<>();
|
||||
|
||||
File dir = new File(BOOK_DIRECTORY);
|
||||
for (File f : dir.listFiles()) {
|
||||
Scanner sc = new Scanner(f);
|
||||
String title = sc.nextLine().substring("Title: ".length());
|
||||
String author = sc.nextLine().substring("Author: ".length());
|
||||
|
||||
ret.add(new Book(title, author));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user