Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kobzar search homework #13

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
.idea/
*.iml

# Compiled class file
*.class

Expand Down
23 changes: 10 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
# hh-school-search
## Дз по поиску

Реализовать свой простой поиск на java, который может работать в 2 режимах:
### Сборка проекта
mvn clean package

1. Индексация: на вход подаётся название файла(директории) индекса и исходный файл, где каждая строка является отдельным документом в индексе, и происходит построение индекса, который записывается в файл(директорию).
2. Поиск: на вход подаётся название файла индекса и запрос, на выходе получаем список документов подходящих под этот запрос.
### Запуск в режиме индексации
В директории для индекса создастся файл index.json

Начать можно с написания наивной реализации инвертированного индекса и запросов по одному слову. В итоге должна получиться jar-ка, которая может работать в 2 режимах. Сдавать в виде PR к этому репозиторию с инструкцией для сборки и запуска, и списком что было реализованно.
java -jar target/search-1-jar-with-dependencies.jar index <директория куда положить файл индекса> <путь к индексируемому файлу>

## Доп. задания (не обязательно, в порядке усложнения):
* написать реализацию запросов AND и NOT
* написать реализацию фразовых запросов
* применить оптимизации при построении индекса из лекции
* написать реализацию OR с задаваемым минимальным количеством вхождений (пример: есть запрос java OR scala OR kotlin, мы хотим все документы где есть минимум 2 слова)
***Пример:*** java -jar target/search-1-jar-with-dependencies.jar index src/main/resources src/main/resources/test.txt

## Срок сдачи
### Запуск в режиме поиска
java -jar target/search-1-jar-with-dependencies.jar search <путь к файлу индекса> <слово для поиска>

31.01.2019 23:59
***Пример:*** java -jar target/search-1-jar-with-dependencies.jar search src/main/resources/index.json следует

## UPD 1

не использовать сторонние библиотеки полнотекста (lucene)
### Реализован только поиск по одному слову
53 changes: 53 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>search</groupId>
<artifactId>search</artifactId>
<version>1</version>

<dependencies>
<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>Main</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id> <!-- this is used for inheritance merges -->
<phase>package</phase> <!-- bind to the packaging phase -->
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

<properties>
<maven.compiler.target>11</maven.compiler.target>
<maven.compiler.source>11</maven.compiler.source>
</properties>

</project>
20 changes: 20 additions & 0 deletions src/main/java/Document.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
public class Document {
private String url;
private String content;

public String getUrl() {
return url;
}

public String getContent() {
return content;
}

public void setUrl(String url) {
this.url = url;
}

public void setContent(String content) {
this.content = content;
}
}
60 changes: 60 additions & 0 deletions src/main/java/Index.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import java.io.IOException;
import java.lang.reflect.Type;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

public class Index {

private Map<String, ArrayList<Integer>> revertIndex = new HashMap<>();

public Map<String, ArrayList<Integer>> getRevertIndex() {
return revertIndex;
}

public Index(Path path) {
loadIndex(path);
}

public Index() {
}

public void addPair(String word, Integer docId) {
if (revertIndex.containsKey(word)) {
ArrayList<Integer> list = revertIndex.get(word);
if (!list.contains(docId))
revertIndex.get(word).add(docId);
} else {
ArrayList<Integer> list = new ArrayList<>();
list.add(docId);
revertIndex.put(word, list);
}
}

public void saveIndex(Path path) {
try {
Files.writeString(path, new Gson().toJson(revertIndex));
System.out.println("Index file was created here: " + path);
} catch (IOException e) {
e.printStackTrace();
}
}

public void loadIndex(Path path) {
try {
String json = Files.readString(path);
Type indexType = new TypeToken<HashMap<String, ArrayList<Integer>>>(){}.getType();
revertIndex = new Gson().fromJson(json, indexType);
} catch (IOException e) {
e.printStackTrace();
}

}

}

48 changes: 48 additions & 0 deletions src/main/java/IndexBuilder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;


public class IndexBuilder {

private Path indexDir;
private Path filePath;
private Index index;

public IndexBuilder(Path indexDir, Path filePath) {
this.indexDir = Paths.get(indexDir + "/index.json");
this.filePath = filePath;
this.index = new Index();
}

public void buildIndex() {
try {
Integer docId = 0;
List<String> lines = Files.readAllLines(filePath);
for (String line : lines) {
// Normalize text
String text = line;
text = TextNormalizer.cleanOutPunct(text);
text = TextNormalizer.toLowerCase(text);
Set<String> words = new HashSet<>(Arrays.asList(TextNormalizer.split(text)));

// Lemmatize

// Fill in index
for (String word : words) {
index.addPair(word, docId);
}
docId++;
}
index.saveIndex(indexDir);
} catch (IOException e) {
e.printStackTrace();
}
}

}
22 changes: 22 additions & 0 deletions src/main/java/Main.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Path;
import java.nio.file.Paths;

public class Main {
public static void main(String[] args) {
if (args.length == 0)
System.out.println("Arguments are required");
else if (args[0].equals("index")) {
Path indexDir = Paths.get(args[1]);
Path filePath = Paths.get(args[2]);
new IndexBuilder(indexDir, filePath).buildIndex();
} else if (args[0].equals("search")) {
Path indexPath = Paths.get(args[1]);
String request = args[2];
System.out.println("This word is contained in the following docs: " +
Searcher.search(indexPath, request.toLowerCase()));
}
}
}
10 changes: 10 additions & 0 deletions src/main/java/Searcher.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;

public class Searcher {

public static List<Integer> search(Path indexPath, String request) {
return new Index(indexPath).getRevertIndex().getOrDefault(request, new ArrayList<>());
}
}
20 changes: 20 additions & 0 deletions src/main/java/TextNormalizer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import java.util.Arrays;

public class TextNormalizer {

public static String cleanOutPunct(String s) {
return s.replaceAll("\\p{Punct}"," ");
}

public static String toLowerCase(String s) {
return s.toLowerCase();
}

public static String[] split(String s) {
return s.split("\\s+");
}

public static String[] deleteOneLetterWords(String[] words) {
return (String[]) Arrays.stream(words).map(word -> word.length() > 1).toArray();
}
}
1 change: 1 addition & 0 deletions src/main/resources/index.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"собой":[0,2,8],"количественный":[6],"развития":[1,2,3,5],"место":[1,9],"важную":[6],"играет":[6],"позволяет":[4,5],"идейные":[7],"задач":[7],"сфера":[6],"роль":[6],"широким":[5],"участниками":[7],"еще":[12],"другой":[9],"пропагандистское":[3,8],"высшего":[7],"не":[2,6],"строка":[12],"предложений":[4],"внедрения":[0,2,8],"нас":[3],"проблем":[1],"настолько":[1],"кадров":[1,9],"финансовых":[9,10],"пооо":[11],"обучения":[1,9],"модели":[2],"обеспечение":[3,8],"новая":[4],"направлений":[5],"анализа":[3],"однако":[2,6],"а":[8],"модель":[4],"в":[6,7],"одна":[12],"и":[0,1,2,6,9,10],"развитие":[0],"требуют":[3],"с":[5,9],"стороны":[9],"от":[3],"очевидна":[1],"условий":[9,10],"укрепление":[0],"модернизации":[1,2,9],"нашей":[3,6,8],"авто":[11],"значение":[4,5],"постоянный":[6],"поп":[11],"рамки":[1,9],"информационно":[3,8],"порядка":[7],"что":[0,1,2,6],"деятельности":[3,4,8],"прогрессивного":[5],"за":[0,2,8],"оценить":[4,5],"постоянное":[2,8],"существенных":[9,10],"подготовки":[10],"способствует":[10],"показывает":[0],"активом":[5],"равным":[4,5],"рост":[6],"позиций":[7],"следует":[2,6],"практика":[0],"влечет":[0,2,8],"организационной":[4],"этих":[1],"занимаемых":[7],"реализации":[10],"значимость":[1],"соображения":[7],"консультация":[5],"формировании":[7],"форм":[1,3],"забывать":[2,6],"образом":[4,5],"активности":[6],"процесс":[0,2,8],"поставленных":[7],"административных":[9,10],"новых":[4],"также":[8],"повседневная":[0],"структуры":[0],"отношении":[7]}
13 changes: 13 additions & 0 deletions src/main/resources/test.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Повседневная практика показывает, что укрепление и развитие структуры влечет за собой процесс внедрения и
модернизации форм развития. Значимость этих проблем настолько очевидна, что рамки и место обучения кадров
влечет за собой процесс внедрения и модернизации модели развития. Не следует, однако забывать, что постоянное
информационно-пропагандистское обеспечение нашей деятельности требуют от нас анализа форм развития.
Равным образом новая модель организационной деятельности позволяет оценить значение новых предложений.
Равным образом консультация с широким активом позволяет оценить значение направлений прогрессивного развития.
Не следует, однако забывать, что постоянный количественный рост и сфера нашей активности играет важную роль в
формировании позиций, занимаемых участниками в отношении поставленных задач. Идейные соображения высшего порядка,
а также постоянное информационно-пропагандистское обеспечение нашей деятельности влечет за собой процесс внедрения
и модернизации существенных финансовых и административных условий. С другой стороны рамки и место обучения кадров
способствует подготовки и реализации существенных финансовых и административных условий.
авто, пооо поп
еще одна строка