أين / كيفية احتواء SOLR في تطبيق ASP.NET MVC (باستخدام نمط NHIBERNATE / ROPOSTORY)

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

سؤال

أنا حاليًا في منتصف التطبيق القائم على أسئلة / إجابة كبيرة بشكل معقول (نوع من مثل StackOverflow / Answersbag.com) نحن نستخدم SQL (Azure) و Nhibernate للوصول إلى البيانات و MVC لتطبيق واجهة المستخدم.

حتى الآن ، يكون المخطط تقريبًا على غرار Stackoverflow DB ، بمعنى أن لدينا واحدة بريد الجدول (يحتوي على كل من الأسئلة / الإجابات)

ربما ستستخدم شيئًا على غرار واجهة المستودع التالي:

public interface IPostRepository
{
    void PutPost(Post post);
    void PutPosts(IEnumerable<Post> posts);

    void ChangePostStatus(string postID, PostStatus status);

    void DeleteArtefact(string postId, string artefactKey);
    void AddArtefact(string postId, string artefactKey);

    void AddTag(string postId, string tagValue);
    void RemoveTag(string postId, string tagValue);

    void MarkPostAsAccepted(string id);
    void UnmarkPostAsAccepted(string id);

    IQueryable<Post> FindAll();
    IQueryable<Post> FindPostsByStatus(PostStatus postStatus);
    IQueryable<Post> FindPostsByPostType(PostType postType);
    IQueryable<Post> FindPostsByStatusAndPostType(PostStatus postStatus, PostType postType);
    IQueryable<Post> FindPostsByNumberOfReplies(int numberOfReplies);
    IQueryable<Post> FindPostsByTag(string tag);
}

سؤالي هو: أين / كيف يمكنني تناسب SOLR في هذا للحصول على هذا "المشاركات" بشكل أفضل (سأستخدم Solrnet للتواصل الفعلي مع Solr)

من الناحية المثالية ، سأستخدم SQL DB مجرد متجر مستمر- الجزء الأكبر من العمليات المذكورة أعلاه سوف ينتقل إلى نوع من فئة solrfinder (أو شيء من هذا القبيل)

خاصية الجسم هي التي تسبب المشكلات حاليًا - إنها كبيرة إلى حد ما ، وتبطئ الاستعلامات على SQL.

مشكلتي الرئيسية ، على سبيل المثال ، إذا قام شخص ما "بتحديث" منشور - يضيف علامة جديدة ، على سبيل المثال ، فإن هذا المنشور كله سيحتاج إلى إعادة الفهرسة. من الواضح أن القيام بذلك سيتطلب استعلامًا كهذا:

"حدد * من post حيث id = xyz"

هذا بالطبع ، يكون بطيئا جدا. Solrnet لديه منشأة nhibernate- لكنني أعتقد أن هذه ستكون نفس النتيجة أعلاه؟

فكرت في طريقة للتغلب على هذا ، والتي أود أن آرائك حول:

  • إضافة المعرف إلى قائمة انتظار (Amazon SQS أو شيء من هذا القبيل - أحب سهولة الاستخدام مع هذا)
  • وجود خدمة (أو مجموعة من الخدمات) في مكان ما يقوم بالاستعلام المذكور أعلاه ، وإنشاء المستند ، وإعادة إضافةه إلى Solr.

مشكلة أخرى أواجهها مع تصميمي:من أين يجب استدعاء طريقة (إعادة الفهرسة "؟ وحدة تحكم MVC؟ أو هل يجب أن يكون لدي فئة من نوع "postervice" ، تلتف مثيل IpoStrepository؟

يتم استلام أي مؤشرات بشكل كبير على هذا واحد!

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

المحلول

على موقع التجارة الإلكترونية التي أعمل من أجلها ، نستخدم SOLR لتوفير FACKING FACETING والبحث في كتالوج المنتج. (بشروط غير Solr Geek ، هذا يعني أن "بطاقات ATI (34) ، NVIDIA (23) ، Intel (5)" من روابط الملاحة التي يمكنك استخدامها للتنقل من خلال كتالوجات المنتجات على مواقع مثل Zappos ، Amazon ، Newegg ، و Lowe's.)

هذا لأن Solr مصمم للقيام بهذا النوع من الأشياء بسرعة وبصحة جيدة ، ومحاولة القيام بهذا النوع من الأشياء بكفاءة في قاعدة بيانات علائقية تقليدية ، لن يحدث ، إلا إذا كنت تريد البدء في إضافة وإزالة الفهارس على تطير واذهب بالكامل eav ، وهو مجرد سعال ماجنتو سعال غبي. لذا فإن قاعدة بيانات SQL Server الخاصة بنا هي مخزن البيانات "الموثوق" ، كما أن فهارس SOLR هي "توقعات" للقراءة فقط لتلك البيانات.

أنت معي حتى الآن لأنه يبدو أنك في موقف مماثل. تتمثل الخطوة التالية في تحديد ما إذا كان من المقبول أم لا أن البيانات الموجودة في مؤشر SOLR قد تكون قديمة قليلاً. ربما قبلت حقيقة أنه سيكون قديمة إلى حد ما ، لكن القرارات التالية موجودة

  • ما مدى قديمة جدا؟
  • متى أقدر السرعة أو الاستعلام عن الميزات على الروتين؟

على سبيل المثال ، لدي ما أسميه "العامل" ، وهي خدمة Windows التي تستخدم Quartz.net لتنفيذ ج# IJob التطبيقات بشكل دوري. كل 3 ساعات ، واحدة من هذه الوظائف التي يتم تنفيذها هي RefreshSolrIndexesJob, ، وكل هذه الوظيفة هي ping an HttpWebRequest أكثر من http://solr.example.com/dataimport?command=full-import. هذا لأننا نستخدم Solr المدمج في DataImpathandler لامتصاص البيانات من قاعدة بيانات SQL ؛ يتعين على الوظيفة فقط "لمس" عنوان URL بشكل دوري لجعل المزامنة تعمل. نظرًا لأن DataImpathandler يرتكب التغييرات بشكل دوري ، فإن كل هذا يعمل بشكل فعال في الخلفية ، شفافًا لمستخدمي موقع الويب.

هذا يعني أن المعلومات الموجودة في كتالوج المنتج يمكن أن تصل إلى 3 ساعات. قد ينقر المستخدم على رابط لـ "Medium in Stock (3)" على صفحة الكتالوج (نظرًا لأن هذا النوع من البيانات المخصصة يتم إنشاءه عن طريق الاستعلام الصفحة ، معلومات الكمية هي واحدة من الأشياء القليلة ليس تخزين مؤقتًا واستفسرت مباشرة ضد قاعدة البيانات). هذا أمر مزعج ، ولكن نادرًا بشكل عام في سيناريونا بشكل خاص (نحن أعمال صغيرة معقولة وليس الذي - التي ارتفاع حركة المرور) ، وسيتم إصلاحه في 3 ساعات على أي حال عندما نعيد بناء الفهرس بالكامل مرة أخرى من نقطة الصفر ، لذلك قبلنا هذا كمقايضة معقولة.

إذا تمكنت من قبول هذه الدرجة من "الرواية" ، فإن عملية العمال في الخلفية هذه هي وسيلة جيدة للذهاب. يمكنك أخذ نهج "إعادة بناء كل شيء كل بضع ساعات" ، أو يمكن لمستودعك إدراج المعرف في طاولة ، على سبيل المثال ، على سبيل المثال ، dbo.IdentitiesOfStuffThatNeedsUpdatingInSolr, ، ثم يمكن لعملية الخلفية مسحًا دوريًا من خلال هذا الجدول وتحديث تلك المستندات في SOLR فقط إذا لم يكن إعادة بناء الفهرس بالكامل من نقطة الصفر غير معقولة بالنظر إلى حجم مجموعة البيانات الخاصة بك.

تتمثل النهج الثالث في أن تولد مستودعك سلسلة خلفية يقوم بتحديث فهرس SOLR فيما يتعلق بهذا المستند الحالي بشكل أو بآخر في نفس الوقت ، وبالتالي فإن البيانات قديمة فقط لبضع ثوانٍ:

class MyRepository
{
    void Save(Post post)
    {
         // the following method runs on the current thread
         SaveThePostInTheSqlDatabaseSynchronously(post);

         // the following method spawns a new thread, task,
         // queueuserworkitem, whatevever floats our boat this week,
         // and so returns immediately
         UpdateTheDocumentInTheSolrIndexAsynchronously(post);
    }
}

ولكن إذا انفجر هذا لسبب ما ، فقد تفوتك تحديثات في SOLR ، لذلك لا يزال من الجيد أن يكون Solr يقوم "بتفجير كل شيء وينعش" ، أو لديك خدمة من نوع العامل الخلفية التي تتحقق من الخارج- من البيانات في Solr الجميع مرة واحدة في القمر الأزرق.

أما بالنسبة للاستعلام عن هذه البيانات من SOLR ، فهناك بعض الأساليب التي يمكنك اتباعها. الأول هو إخفاء حقيقة أن Solr موجود بالكامل عبر طرق المستودع. أنا شخصياً لا أوصي بذلك لأن فرص مخطط SOLR الخاص بك سيتم تصميمها بلا خجل وفقًا لاجتماع واجهة المستخدم التي ستحصل على هذه البيانات ؛ لقد اتخذنا بالفعل قرارًا باستخدام SOLR لتوفير المعلومات السهلة والفرز والعرض السريع للمعلومات ، لذلك قد نستخدمها إلى أقصى حد. هذا يعني جعلها صريحة في التعليمات البرمجية عندما نعني الوصول إلى SOLR وعندما نعني الوصول إلى كائن قاعدة البيانات غير المحدّثة وغير المقيد.

في حالتي ، انتهى بي الأمر باستخدام nhibernate للقيام بالوصول إلى crud (تحميل an ItemGroup, ، مع استقبال قواعد التسعير الخاصة بها ، ثم حفظه مرة أخرى) ، والتخلي عن نمط المستودع لأنني لا أرى عادةً قيمته عندما تقوم Nhibernate وأرسمه بالفعل بتجريد قاعدة البيانات. (هذا هو اختيار شخصي.)

ولكن عند الاستعلام عن البيانات ، أعرف جيدًا إذا كنت أستخدمها لأغراض موجهة نحو الكتالوج (أهتم بها سرعة و الاستعلام) أو للعرض في جدول على تطبيق إداري خلفي (أهتم به عملة). للاستعلام على موقع الويب ، لدي واجهة تسمى ICatalogSearchQuery. لديها Search() الطريقة التي تقبل أ SearchRequest حيث أحدد بعض المعلمات-الجوانب المحددة ، وشروط البحث ، ورقم الصفحة ، وعدد العناصر لكل صفحة ، وما إلى ذلك SearchResult-جوانب التخلص من النتائج ، والنتائج في هذه الصفحة ، وما إلى ذلك.

حيث يصبح الأمر مثيرًا للاهتمام هو أن تنفيذ ذلك ICatalogSearchQuery يستخدم قائمة من ICatalogSearchStrategyS تحت. الإستراتيجية الافتراضية ، SolrCatalogSearchStrategy, ، يضرب Solr مباشرة عبر طراز قديم عادي HttpWebRequest وتحليل XML في HttpWebResponse (وهو أمر أسهل بكثير في الاستخدام ، IMHO ، من بعض مكتبات عملاء SOLR ، على الرغم من أنها ربما تكون أفضل منذ آخر مرة نظرت إليها منذ أكثر من عام). إذا كانت هذه الاستراتيجية تطرح استثناء أو تدقيات لسبب ما ، فإن ذلك DatabaseCatalogSearchStrategy يضرب قاعدة بيانات SQL مباشرة-على الرغم من أنها تتجاهل بعض المعلمات من SearchRequest, ، مثل الوجه أو البحث عن النص المتقدم ، نظرًا لأن هذا غير فعال للقيام به هناك وهو السبب الكامل في أننا نستخدم SOLR في المقام الأول. والفكرة هي أن SOLR عادة ما تقوم بالإجابة على طلبات البحث الخاصة بي بسرعة في المجد الكامل ، ولكن إذا انخفض شيء ما وارتقل Solr ، فإن صفحات الكتالوج في الموقع لا تزال تعمل في "وضع الوظيفة المخفضة" عن طريق ضرب قاعدة البيانات مع مجموعة ميزة محدودة مباشرة. (نظرًا لأننا أوضحنا في الكود أن هذا بحث ، فإن هذه الاستراتيجية يمكن أن تأخذ بعض الحريات في تجاهل بعض معلمات البحث دون القلق بشأن التأثير على العملاء بشدة.)

الوجبات الرئيسية: المهم هو أن قرار إجراء استعلام مقابل متجر بيانات ربما مقابل مخزن البيانات الموثوق به قد تم صريح-إذا أردت بيانات سريعة ، ربما لا معنى لها مع ميزات البحث المتقدمة ، أستخدمها ICatalogSearchQuery. إذا أردت بيانات بطيئة ومحدثة مع إمكانية إدراج/تحديث/حذف ، فأنا أستخدم الاستعلامات المسماة لـ Nhibernate (أو مستودع في قضيتك). وإذا قمت بإجراء تغيير في قاعدة بيانات SQL ، فأنا أعلم أن خدمة العمال خارج العملية ستقوم بتحديث SOLR في النهاية ، مما يجعل الأمور متسقة في النهاية. (وإذا كان هناك شيء مهم حقًا ، فيمكنني بث حدث أو Ping the Solr Store مباشرةً ، وأخبره بالتحديث ، ربما في موضوع خلفية إذا اضطررت إلى ذلك.)

أتمنى أن يمنحك هذا بعض البصيرة.

نصائح أخرى

نستخدم SOLR للاستعلام عن قاعدة بيانات منتج كبيرة. حوالي مليون منتج ، و 30 متجرا.

ما فعلناه هو أننا استخدمنا المشغلات على جدول المنتجات وجداول الأسهم على خادم SQL الخاص بنا.

في كل مرة يتم فيها تغيير صف ، يعلم المنتج أن المنتج يتم إدخاله. ولدينا خدمة Windows التي تستحوذ على هذه المنتجات ونشرها إلى Solr كل 10 ثوان. (بحد 100 منتج لكل دفعة).

إنها معلومات فائقة الكفاءة ، في الوقت الفعلي تقريبًا للسهم.

إذا كان لديك حقل نص كبير (حقل "جسمك") ، فعندئذ أعد الفهرس في الخلفية. الحلول التي ذكرتها (قائمة الانتظار أو خدمة الخلفية الدورية) ستفعل.

يجب أن تكون وحدات تحكم MVC غافلة عن هذه العملية.

لقد لاحظت أن لديك iqueryables في واجهة المستودع الخاص بك. Solrnet لا لديك مزود LINQ. على أي حال ، إذا كانت هذه العمليات هي كل ما ستفعله بـ SOLR (أي عدم وجود جوانب) ، فقد ترغب في التفكير في استخدام lucene.net بدلاً من ذلك ، وهو ما يفعل لديك مزود LINQ.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top