Как вы запрашиваете коллекции объектов в Java (подобно критериям/SQL)?

StackOverflow https://stackoverflow.com/questions/93417

  •  01-07-2019
  •  | 
  •  

Вопрос

Предположим, у вас есть коллекция из нескольких сотен объектов в памяти, и вам нужно запросить этот список, чтобы вернуть объекты, соответствующие какому-либо запросу SQL или критерию.Например, у вас может быть список объектов «Автомобили», и вы хотите вернуть все автомобили, выпущенные в 1960-е годы, с номерным знаком, начинающимся с AZ, упорядоченные по названию модели автомобиля.

я знаю о ДжоSQL, кто-нибудь использовал это или имел опыт работы с другими/собственными решениями?

Это было полезно?

Решение

я использовал Apache Commons JXPath в производственном приложении.Он позволяет применять выражения XPath к графикам объектов в Java.

Другие советы

Фильтрация — один из способов сделать это, как обсуждалось в других ответах.

Однако фильтрация не масштабируется.На первый взгляд сложность времени может показаться O(н) (т.е.уже не масштабируемо, если количество объектов в коллекции будет расти), а на самом деле потому, что один или больше тесты необходимо применять к каждому объекту в зависимости от запроса, точнее, временная сложность равна O(н т) где т — количество тестов, применяемых к каждому объекту.

Таким образом, производительность будет снижаться по мере добавления в коллекцию дополнительных объектов. и/или по мере увеличения количества тестов в запросе.

Есть еще один способ сделать это, используя индексацию и теорию множеств.

Один из подходов заключается в том, чтобы строить индексы на поля внутри объектов, хранящихся в вашей коллекции и которые вы впоследствии протестируете в своем запросе.

Допустим, у вас есть коллекция Car предметы и все Car объект имеет поле color.Допустим, ваш запрос эквивалентен «SELECT * FROM cars WHERE Car.color = 'blue'".Вы можете построить индекс на Car.color, что в основном будет выглядеть так:

'blue' -> {Car{name=blue_car_1, color='blue'}, Car{name=blue_car_2, color='blue'}}
'red'  -> {Car{name=red_car_1, color='red'}, Car{name=red_car_2, color='red'}}

Затем задан запрос WHERE Car.color = 'blue', набор синих машин можно получить за O(1) временная сложность.Если бы в вашем запросе были дополнительные тесты, вы могли бы протестировать каждый автомобиль в этом запросе. набор кандидатов чтобы проверить, соответствует ли он остальным тестам в вашем запросе.Поскольку набор кандидатов, скорее всего, будет значительно меньше всей коллекции, временная сложность меньше, чем О(н) (в инженерном смысле см. комментарии ниже).Производительность не ухудшается столько, когда в коллекцию добавляются дополнительные объекты.Но это еще не идеально, читайте дальше.

Другой подход я бы назвал постоянный индекс запроса.Объяснить:при обычной итерации и фильтрации коллекция повторяется, и каждый объект проверяется на соответствие запросу.Таким образом, фильтрация аналогична выполнению запроса к коллекции.Постоянный индекс запроса будет наоборот: вместо этого коллекция будет выполняться по запросу, но только один раз для каждого объекта в коллекции, даже если к коллекции можно запрашивать любое количество раз.

А постоянный индекс запроса это было бы похоже на регистрацию запроса с помощью какого-то интеллектуальная коллекция, так что при добавлении и удалении объектов из коллекции коллекция будет автоматически проверять каждый объект на соответствие всем постоянным запросам, которые были в ней зарегистрированы.Если объект соответствует постоянному запросу, коллекция может добавить/удалить его в/из набора, предназначенного для хранения объектов, соответствующих этому запросу.Впоследствии объекты, соответствующие любому из зарегистрированных запросов, могут быть получены за O(1) временная сложность.

Информация выше взята из CQEngine (система запросов к коллекциям).По сути, это механизм запросов NoSQL для извлечения объектов из коллекций Java с помощью SQL-подобных запросов без затрат на итерацию по коллекции.Он построен на идеях, изложенных выше, а также на некоторых других.Отказ от ответственности:Я автор.Это открытый исходный код и находится в Maven Central. Если вы нашли это полезным, пожалуйста, проголосуйте за этот ответ!

да, я знаю, что это старый пост, но технологии появляются каждый день, и со временем ответ изменится.

Я думаю, что это хорошая проблема, которую можно решить с помощью LambdaJ.Вы можете найти это здесь:http://code.google.com/p/lambdaj/

Вот вам пример:

ИЩИТЕ АКТИВНЫХ КЛИЕНТОВ // (Итерируемая версия)

List<Customer> activeCustomers = new ArrayList<Customer>();  
for (Customer customer : customers) {  
  if (customer.isActive()) {  
    activeCusomers.add(customer);  
  }  
}  

Версия LambdaJ

List<Customer> activeCustomers = select(customers, 
                                        having(on(Customer.class).isActive()));  

Конечно, такая красота влияет на выступление (немного...в среднем в 2 раза), но можно ли найти более читабельный код?

Он имеет множество функций, другим примером может быть сортировка:

Сортировка итеративная

List<Person> sortedByAgePersons = new ArrayList<Person>(persons);
Collections.sort(sortedByAgePersons, new Comparator<Person>() {
        public int compare(Person p1, Person p2) {
           return Integer.valueOf(p1.getAge()).compareTo(p2.getAge());
        }
}); 

Сортировка с помощью лямбды

List<Person> sortedByAgePersons = sort(persons, on(Person.class).getAge()); 

Продолжая Comparator тему, вы также можете взглянуть на Коллекции Google API.В частности, у них есть интерфейс под названием Предикат, который выполняет аналогичную роль Comparator, поскольку это простой интерфейс, который может использоваться методом фильтрации, например Наборы.фильтр.Они включают в себя целую кучу реализаций составных предикатов для выполнения операторов AND, OR и т. д.

В зависимости от размера вашего набора данных использование этого подхода может иметь больше смысла, чем подход SQL или внешней реляционной базы данных.

Если вам нужно одно конкретное совпадение, вы можете использовать класс, реализующий Comparator, затем создать автономный объект со всеми включенными хешированными полями и использовать его для возврата индекса совпадения.Если вы хотите найти в коллекции более одного (потенциально) объекта, вам придется обратиться к такой библиотеке, как JoSQL (которая хорошо сработала в тех тривиальных случаях, для которых я ее использовал).

В общем, я склонен встраивать Derby даже в свои небольшие приложения, использую аннотации Hibernate для определения классов моделей и позволяю Hibernate заниматься схемами кэширования, чтобы все было быстро.

Я бы использовал компаратор, который принимает диапазон лет и образец номерного знака в качестве входных параметров.Затем просто просмотрите свою коллекцию и скопируйте подходящие объекты.При таком подходе вы, вероятно, в конечном итоге создадите целый пакет пользовательских компараторов.

А Comparator вариант неплох, особенно если вы используете анонимные классы (чтобы не создавать избыточные классы в проекте), но в конечном итоге, когда вы смотрите на поток сравнений, это почти все равно, что самому перебрать всю коллекцию, указав именно тот Условия сопоставления предметов:

if (Car car : cars) {
    if (1959 < car.getYear() && 1970 > car.getYear() &&
            car.getLicense().startsWith("AZ")) {
        result.add(car);
    }
}

Потом сортировка...это может быть занозой в спине, но, к счастью, есть класс Collections И его sort методы, один из которых получает Comparator...

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top