كيف يمكنك الاستعلام عن مجموعات الكائنات في Java (معايير/مثل SQL)؟

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

  •  01-07-2019
  •  | 
  •  

سؤال

لنفترض أن لديك مجموعة من بضع مئات من الكائنات في الذاكرة وتحتاج إلى الاستعلام عن هذه القائمة لإرجاع كائنات تطابق بعض SQL أو معايير مثل الاستعلام.على سبيل المثال، قد يكون لديك قائمة بعناصر السيارات وتريد إرجاع جميع السيارات التي تم تصنيعها خلال الستينيات، مع لوحة ترخيص تبدأ بـ AZ، مرتبة حسب اسم طراز السيارة.

وأنا أعلم عن جوسكل, هل استخدم أي شخص هذا، أو لديه أي خبرة في الحلول الأخرى/المحلية؟

هل كانت مفيدة؟

المحلول

لقد استخدمت أباتشي كومنز 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);  
  }  
}  

نسخة لامبداج

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

وبطبيعة الحال، فإن وجود هذا النوع من الجمال يؤثر على الأداء (قليلاً...بمعدل مرتين)، ولكن هل يمكنك العثور على رمز أكثر قابلية للقراءة؟

لديها العديد من الميزات، مثال آخر يمكن أن يكون الفرز:

فرز تكراري

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 الموضوع، قد ترغب أيضًا في إلقاء نظرة على مجموعات جوجل واجهة برمجة التطبيقات.على وجه الخصوص، لديهم واجهة تسمى فاعل, ، والذي يؤدي دورًا مشابهًا لـ Comparator, ، حيث أنها واجهة بسيطة يمكن استخدامها عن طريق طريقة التصفية، مثل مجموعات.تصفية.وهي تشمل مجموعة كاملة من تطبيقات المسند المركبة، للقيام بـ AND، وORs، وما إلى ذلك.

اعتمادًا على حجم مجموعة البيانات الخاصة بك، قد يكون استخدام هذا الأسلوب أكثر منطقية من استخدام 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