Запрос на объект Java без базы данных
Примечание: Маленький длинный вопрос. Я собираюсь дать щедрость за лучший ответ.
То, что я пытаюсь сделать, это запрос объекта. Вот подробности. У меня есть файл с именем employee.txt
. Поэтому я проанализировал его и сохранил в списке
public static List<Employee> employeeList = new LinkedList<>();
Тогда вот моя логика для запроса.
Возьмите запрос от пользователя, а затем проанализируйте его. Ниже приведена логика запроса через список.
Для примера: вот запрос
select * from Employee where id > 10
Мои коды для этого
String valueToCompare = split[5]; //10
EmployeeCriteria criteria = new EmployeeCriteria(
isId, isName, isSalary, expression,
valueToCompare);
result = EmployeeData.findAll(
EmployeeData.employeeList, criteria);
Вот метод findAll
public static List<Employee> findAll(List<Employee> coll,
ISearch<Employee> chk) {
List<Employee> l = new LinkedList<Employee>();
for (Employee obj : coll) {
if (chk.search(new Employee(obj)))
l.add(obj);
}
return l;
}
И вот мой метод поиска
/**
* Based on the type provided and for given expression it check against the
* given value
*/
@Override
public boolean search(Employee obj) {
if (expression.equals(EQUAL)) {
if (isId()) {
if (obj.getId() == Long.parseLong(valueToCompare)) {
return true;
}
} else if (isName()) {
if (obj.getName().equals(valueToCompare)) {
return true;
}
} else if (isSalary()) {
if (obj.getSalary() == Long.parseLong(valueToCompare)) {
return true;
}
} else {
System.err.println(UserMessage.INVALIDCOLUMN_NAME);
}
} else if (expression.equals(NOT_EQUAL)) {
if (isId()) {
if (!(obj.getId() == Long.parseLong(valueToCompare))) {
return true;
}
} else if (isName()) {
if (!(obj.getName().equals(valueToCompare))) {
return true;
}
} else if (isSalary()) {
if (!(obj.getSalary() == Long.parseLong(valueToCompare))) {
return true;
}
} else {
System.err.println(UserMessage.INVALIDCOLUMN_NAME);
}
} else if (expression.equals(GREATER)) {
if (isId()) {
if ((obj.getId() > Long.parseLong(valueToCompare))) {
return true;
}
} else if (isSalary()) {
if ((obj.getSalary() > Long.parseLong(valueToCompare))) {
return true;
}
} else {
System.err.println(UserMessage.INVALIDCOLUMN_NAME);
}
} else if (expression.equals(LESSER)) {
if (isId()) {
if ((obj.getId() < Long.parseLong(valueToCompare))) {
return true;
}
} else if (isSalary()) {
if ((obj.getSalary() < Long.parseLong(valueToCompare))) {
return true;
}
} else {
System.err.println(UserMessage.INVALID_IDENTIFIER);
}
}
return false;
}
Сообщите мне, хотите ли вы видеть другие коды.
Я просто хочу знать,
Во-первых, LinkedList
- правильная структура данных для использования? Это хорошо работает? Любые улучшения для наилучшего выполнения?
Есть ли лучший способ добиться этого?
Вот несколько примеров:
select * where ID > 100
select * where Name != Ramesh
select * where Salary < 500000
select Name order by Name
select ID
Спасибо за любую помощь. Bounty будет предложено через 2 дня. Я не могу этого сделать сейчас.
Примечание2: Это тест для проверки навыков управления данными, и я не могу использовать какую-либо базу данных.
Ответы
Ответ 1
Нет, это плохо работает. Вы каждый раз просматриваете сотрудников N
. Поэтому, если у вас есть 1 миллион сотрудников, вы будете искать все 1 миллион сотрудников, прежде чем возвращать нужного сотрудника. Даже худшее, если оно не существует, вам придется искать исчерпывающий, прежде чем вы сможете узнать, существует ли он.
Это для использования в производстве? Если это так, просто используйте SQLite или другую простую базу данных. Вы хотите написать один раз и прочитать несколько раз с индексами. Я не могу подчеркнуть, что то, что вы пишете, будет иметь ошибки, и вместо этого вы должны использовать то, что уже было проверено.
Предполагая, что это не для производства, и вы просто развлекаетесь, тогда вы хотите подражать тем, что делают базы данных в реальной жизни. Они создают индексы. Индексы обычно лучше всего описываются как Map<String, List<Employee>>
.
Идея состоит в том, что изначально чтение данных с диска дорого. Но вы читали его один раз. Для каждого измерения Name
, Salary
, ID
и т.д.... вы хотите создать отдельные индексы.
Итак, скажем, вы создавали индекс всех сотрудников по ID. Вы хотели бы сделать что-то вроде:
Map<String, Employee> employeesById = new HashMap<>();
for(Employee e : employees) {
employeesById.put(e.getId(), e);
}
Вышеприведенное предполагает, что идентификаторы сотрудников уникальны. Если это не так, вам нужно создать List<Employee>
. Например, для индекса по имени:
Map<String,List<Employee>> employeesByName = new HashMap<>();
for(Employee e : employees) {
employeesByName.get(e.getName()).add(e); // Make sure to create the array if it doesn't exist
}
Итак, теперь, для чтения, скажем, вы получите SELECT * FROM employees where id = 123;
, просто можете просто вернуть employeesById.get("123")
.
Это решение O(1)
. По мере увеличения размера файла у вас не будет потери производительности. Это, вероятно, самое быстрое решение.
Ответ 2
Чтобы добавить ответ Амира, вы также можете использовать TreeMap<>
вместо HashMap<>
. Базы данных обычно не создают индексы как хеш-карты, а как сбалансированные двоичные деревья, что и есть класс Java TreeMap<>
.
http://docs.oracle.com/javase/8/docs/api/java/util/TreeMap.html
HashMap<>
имеет O (1) поиск ключей, но является точным совпадением только с ключом. TreeMap<>
имеет O (log n) поиск по ключам, но позволяет поиск по диапазону higherKey
, lowerKey
) и разбиение на разделы по диапазону клавиш (subMap
).
Проблема дубликатов может быть решена, если не разрешить их (уникальный ключ) или сохранить значения в списке и линейный поиск подмножества (не уникальный ключ).
Ответ 3
Предполагая, что вас не интересует какое-либо из решение для базы данных в памяти и с использованием Java 8,
Вы должны преобразовать все свои условия в предикат и применить их к потоку. Это позволит использовать функцию Java 8 parallelism http://blog.takipi.com/new-parallelism-apis-in-java-8-behind-the-glitz-and-glamour/
Короче говоря, ваш код может быть намного чище и быстрее
public static Predicate<Employee> isSalaryGreaterThan(Integer salary) {
return p -> p.getSalary() > salary;
}
Predicate predicate1 = isSalaryGreaterThan(50000)
employeeList.stream().filter(predicate1).filter(predicate2)...collect(Collectors.<Employee>toList())