كيفية جعل Laravel و Elasticsearch تصبح أصدقاء

Laravel هو إطاري المفضل حتى الآن. يعجبني أنه يوفر الكثير من الاحتمالات خارج الصندوق. يفكر فريق Laravel في كل جزء من منتجه لجعل الأداة التي تحل جميع المهام الشائعة التي يصطدم بها مطورو الويب أثناء روتينهم.

لقد صنعوا أداة رائعة تساعدك في إنشاء محرك بحث على موقعك. يطلق عليه لارافيل سكاوت. الشيء الوحيد غير السار هنا هو برنامج التشغيل الذي يأتي مع التثبيت الافتراضي لارافيل. إنه سائق الغوليا. بالطبع ، تعد Algolia طريقة جيدة وسريعة لإضافة إمكانيات البحث إلى النماذج الخاصة بك. لكنني وأفترض أن العديد من المطورين الآخرين يفضلون أن يكون Elasticsearch بمثابة برنامج تشغيل افتراضي.

لحسن الحظ ، قدم لنا فريق Laravel فرصة لإنشاء برامج التشغيل الخاصة بنا. هذا أمر سهل للغاية ويمكنك العثور على جميع المعلومات اللازمة بشأن ذلك في مستندات Scout. في هذه المقالة ، سأستخدم الحل الخاص بي ، الذي خلقته لأنني غير راض عن الحلول الحالية. حاولت اتباع إيديولوجية Laravel من أجل إنشاء أداة تتيح لك التعامل مع Elasticsearch بطريقة سهلة للغاية ومريحة.

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

منزل

أفضل استخدام Homestead للتطوير ، وهو جهاز افتراضي يقدمه فريق Laravel. بالنسبة لي إنها طريقة ملائمة لفصل بيئة العمل عن برنامجي وبياناتي الشخصية لمنع الفوضى على الجهاز.

في هذا البرنامج التعليمي ، سأستخدم Homestead ، وبالتالي يتم تقديم جميع تعليمات وحدة التحكم لـ Ubuntu.

إذا كنت تستخدم VM ، فاتصل بجهازك بواسطة SSH وسوف نبدأ في تكوين البرنامج.

تركيب المطاط

لإجراء طلب بحث ، يتعين علينا تثبيت Elasticsearch أولاً. يمكن القيام بذلك بسهولة مع مدير الحزم:

// تنزيل وتثبيت مفتاح التوقيع Elasticsearch
wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -
// تثبيت حزمة apt-transport-https
sudo apt-get install apt-transport-https
/ / احفظ تعريف المخزون
صدى "deb https://artifacts.elastic.co/packages/5.x/apt مستقرة الرئيسية" | sudo tee -a /etc/apt/sources.list.d/elastic-5.x.list
// تثبيت حزمة elasticsearch
sudo apt-get update && sudo apt-get install elasticsearch

لكن كالمعتاد ليس الإجراء الوحيد الذي يتعين علينا القيام به من أجل إنجاحه.

افتح الملف /etc/elasticsearch/elasticsearch.yml مع أي محرر ، على سبيل المثال vim ، وقم بتعيين network.host على المضيف المحلي:

network.host: مضيف محلي

نحتاج الآن إلى إعادة تشغيل الخدمة:

إعادة تشغيل خدمة sudo

يستغرق بعض الوقت لإعادة تشغيل الخدمة. بمجرد الانتهاء من التحقق من أنه يعمل من خلال استعلام http بسيط:

حليقة HTTP: // localhost: 9200 /

يجب عليه إرجاع إجابة مشابهة لما يلي:

{
  "الاسم": "UhEc17r" ،
  "cluster_name": "elasticsearch" ،
  "cluster_uuid": "QoNneSUhTG6EJaA4LMqDlA"،
  "الإصدار" : {
    "الرقم": "5.4.0" ،
    "build_hash": "780f8c4" ،
    "build_date": "2017-04-28T17: 43: 27.229Z" ،
    "build_snapshot": خطأ ،
    "lucene_version": "6.5.0"
  }،
  "سطر الوصف": "أنت تعرف ، للبحث"
}

آمل ألا تكون لديك أي مشاكل هنا ويمكننا المضي قدمًا.

إنشاء مشروع جديد لارافيل

لنقم بإنشاء تثبيت جديد لإطار Laravel. إذا كنت تستخدم Homestead ، فسيكون لديك برنامج تثبيت Laravel خارج الصندوق ، وإذا لم يكن بإمكانك تثبيته باستخدام Composer.

في Homestead تقع جميع المشاريع في دليل Code home. انتقل إلى الدليل وقم بعمل مشروع جديد ، باستخدام مثبت Laravel:

cd ~ / رمز /
laravel بحث جديد تعليمي

في هذا البرنامج التعليمي ، سنستخدم قاعدة بيانات sqlite ، فقط لإبقاء الأمور بسيطة. انتقل إلى نهاية ملف .env عيّن خيار DB_CONNECTION على sqlite والتعليق على خيارات قاعدة البيانات الأخرى:

DB_CONNECTION = سكليتي
# DB_HOST = 127.0.0.1
# DB_PORT = 3306
# DB_DATABASE = منزل
# DB_USERNAME = منزل
# DB_PASSWORD = سر

أخيرًا ، لتخزين البيانات ، يجب علينا إنشاء ملف:

المس قاعدة البيانات / database.sqlite

الكشفية سائق

لقد تحدثنا بالفعل قليلاً عن Laravel Scout. ويضيف البحث عن النص الكامل لنماذج Eloquent الخاصة بك. لقد ذكرت أيضًا أننا سنستخدم محرك Scout مخصص ، لأنه لا يوجد برنامج Elasticsearch خارج الصندوق.

دعنا نثبت الحزمة مع الملحن:

الملحن تتطلب babenkoivan / الكشفية elasticsearch سائق

كما يمكنك تخمين ، سنقوم بعمل بعض التكوينات. أولاً ، انتقل إلى config / app.php وأضف سلسلتين إلى قسم مقدمي الخدمات:

"مقدمي" => [
   // ...
   // الحزمة الكشفية نفسها
   لارافل \ الكشفية \ ScoutServiceProvider :: الفئة،
   
   // سائق Elasticsearch
   ScoutElastic \ ScoutElasticServiceProvider :: الفئة،
   // ...
]

ثانياً ، يتعين علينا نشر إعدادات الحزم لتكوين Scout. قم بتشغيل الأوامر التالية في وحدة التحكم:

بائع الحرفيين php: publish --provider = "Laravel \ Scout \ ScoutServiceProvider"
بائع الحرفيين php: publish --provider = "ScoutElastic \ ScoutElasticServiceProvider"

أخيرًا ، إلحاق SCOUT_DRIVER = مرن بنهاية ملف .env.

مؤشر الفهرس

مؤشر Elasticsearch يشبه قاعدة بيانات في نموذج العلاقات التقليدية ، في حين يشبه Elasticsearch الجدول. يتعين علينا إنشاء كليهما قبل أن نتمكن من إرسال أي بيانات إلى Elasticsearch. سنبدأ من إنشاء فهرس.

في البداية ، سنجعل فئة خاصة - مؤشر الفهرس:

جعل الحرفيين php: مؤشر ، مكون TutorialIndexConfigurator

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

أخيرًا ، دعنا ننشئ كيان فهرس في ElasticSearch وفقًا لمكون الفهرس:

الحرفي php مرن: إنشاء فهرس "App \ TutorialIndexConfigurator"

نماذج قابلة للبحث

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

دعنا نقول أن كل كتاب يحتوي على عنوان ووصف وسنة إصدار ومؤلف. المؤلف ليس له سوى اسم. لنقم أيضًا بالتبسيط التالي: يمكن للمؤلف أن يكتب عدة كتب ، ولكن يمكن كتابة كتاب بواسطة مؤلف واحد فقط.

يمكننا إنشاء نماذج باستخدام أمر الحرفي make:

جعل الحرفيين php: كتاب نموذج للبحث --index-configurator = "TutorialIndexConfigurator" - الهجرة
php artisan make: نموذج للبحث - Author --index-configurator = "TutorialIndexConfigurator" --migration

النماذج القابلة للبحث هي إصدارات موسعة من الإصدارات المعتادة ، ولكن مع بعض السلوك المحدد مسبقًا الذي يسمح لهم بإجراء طلبات البحث في Elasticsearch.

يمكنك ملاحظة أننا قد أجرينا أيضًا عمليات ترحيل وحددنا مكون الفهرس لكل نموذج. هذا أمر مهم ، لأنه يتعين علينا أن نكون صريحين فيما يتعلق باستخدام مؤشر Elasticsearch لنوع Elasticsearch.

يمكنك العثور على كل من (Book.php و Author.php) الملفات التي تم إنشاؤها في مجلد التطبيق للمشروع. سنقوم بتحريرها من أجل تحديد مناظرة لكل نوع بحث علمي. من الضروري تعيين التعيين ، لأنه يخبر Elasticsearch كيفية التعامل مع الحقول.

فيما يلي الرمز الكامل لفئة الكتاب بعد التحرير:

<؟ PHP
مساحة التطبيق
استخدام ScoutElastic \ SearchableModel ؛
كتاب الطبقة يمتد SearchableModel
{
    // لا نريد استخدام الطوابع الزمنية في هذا البرنامج التعليمي
    الطوابع الزمنية العامة $ = false؛
    الفهرس المحمي $ indexConfigurator = TutorialIndexConfigurator :: class؛
// نحن لا نحلل الأرقام ، كل النصوص باللغة الإنجليزية
    تعيين $ المحمية = [
        'الخصائص' => [
            'id' => [
                "اكتب" => "عدد صحيح" ،
                'index' => 'not_analyzed'
            ]،
            'title' => [
                'type' => 'string' ،
                "محلل" => "الإنجليزية"
            ]،
            "الوصف" => [
                'type' => 'string' ،
                "محلل" => "الإنجليزية"
            ]،
            'السنة' => [
                "اكتب" => "عدد صحيح" ،
                'index' => 'not_analyzed'
            ]،
            'author_id' => [
                "اكتب" => "عدد صحيح" ،
                'index' => 'not_analyzed'
            ]
        ]
    ].
    // كل كتاب ينتمي إلى مؤلف واحد
    مؤلف الوظيفة العامة ()
    {
        return $ this-> ينتمي إلى (Author :: class) ؛
    }
}

رمز نموذج المؤلف أدناه:

<؟ PHP
مساحة التطبيق
استخدام ScoutElastic \ SearchableModel ؛
يمتد المؤلف المؤلف SearchableModel
{
   الطوابع الزمنية العامة $ = false؛
   الفهرس المحمي $ indexConfigurator = TutorialIndexConfigurator :: class؛
   تعيين $ المحمية = [
        'الخصائص' => [
            'id' => [
                "اكتب" => "عدد صحيح" ،
                'index' => 'not_analyzed'
            ]،
            'name' => [
                'type' => 'string' ،
                "محلل" => "الإنجليزية"
            ]
        ]
    ].
    // يمكن لكل مؤلف أن يكتب عدة كتب
    كتب الوظائف العامة ()
    {
        return $ this-> hasMany (Book :: class)؛
    }
}

الهجرات

أثناء إنشاء النموذج ، قمنا أيضًا بإنشاء ملفي ترحيل. يمكنك العثور عليها في مجلد قاعدة البيانات / الهجرات. ابحث عن الملف الذي ينتهي بـ books_table.php ووصف حقول الجدول كما يلي:

<؟ PHP
استخدام Illuminate \ Support \ Facades \ Schema؛
استخدام Illuminate \ Database \ Schema \ Blueprint؛
استخدام Illuminate \ Database \ Migrations \ Migration؛
الطبقة CreateBooksTable يمتد الهجرة
{
    وظيفة عامة تصل ()
    {
        مخطط :: create ('books'، function (Blueprint $ table) {
            $ table-> الزيادات ( 'الهوية')؛
            $ table-> سلسلة ( 'عنوان')؛
            $ table-> النص ( 'وصف')؛
            $ table-> عدد صحيح ( 'العام')؛
            $ table-> عدد صحيح ( 'author_id')؛
        })؛
    }
    وظيفة عامة أسفل ()
    {
        مخطط :: dropIfExists ( 'كتب')؛
    }
}

الآن يمكنك العثور على ملفhors_table.php ووصف حقول جدول المؤلفين:

<؟ PHP
استخدام Illuminate \ Support \ Facades \ Schema؛
استخدام Illuminate \ Database \ Schema \ Blueprint؛
استخدام Illuminate \ Database \ Migrations \ Migration؛
فئة CreateAuthorsTable يمتد الترحيل
{
    وظيفة عامة تصل ()
    {
        مخطط :: create ('للمؤلفين' ، الوظيفة (جدول مخطط $) {
            $ table-> الزيادات ( 'الهوية')؛
            $ table-> سلسلة ( 'اسم')؛
        })؛
    }
    وظيفة عامة أسفل ()
    {
        مخطط :: dropIfExists ( 'الكتاب')؛
    }
}

لإنشاء جداول ، قم بتشغيل أمر الترحيل في وحدة التحكم:

الحرفي php تهاجر

بيانات وهمية

للعب مع محرك البحث نحتاج إلى بعض البيانات. أسهل طريقة للحصول عليها هي إنشاء بعض البيانات المزيفة. دعنا نضيف مصانع لنموذج الكتاب ونموذج المؤلف في ملف قاعدة البيانات / المصانع / ModelFactory.php:

<؟ PHP
$ factory-> define (App \ Author :: class ، وظيفة (Faker \ Generator $ faker) {
    إرجاع [
        'name' => "{$ faker-> firstName} {$ faker-> lastName}"
    ].
})؛
$ factory-> define (App \ Book :: class ، وظيفة (Faker \ Generator $ faker) {
    إرجاع [
        'title' => ucfirst ($ faker-> realText (15)) ،
        'description' => $ faker-> realText (200) ،
        "السنة" => $ faker-> السنة ،
        'author_id' => function () {
        // نأخذ المؤلف العشوائي الأول من الجدول
            إرجاع التطبيق \ المؤلف :: inRandomOrder () -> first () -> id؛
        }
    ].
})؛

لدى Laravel وحدة تحكم PHP رائعة ، تسمى Tinker. يمكنك تشغيله باستخدام الحرفي:

فب الحرفي العبث

لنقم بإنشاء 50 مؤلفًا:

factory (App \ Author :: class، 50) -> create ()

و 200 كتاب:

factory (App \ Book :: class، 200) -> create ()

عظيم! الآن لدينا البيانات للعب مع.

استعلامات البحث

تتم جميع الاستعدادات ، ونحن على استعداد لإجراء أول استعلام بحث لدينا. دعنا نعثر على جميع الكتب التي تحتوي على الكلمة Alice:

// في هذا الاستعلام نقول Elasticsearch - أعطنا 10 سجلات ، تحتوي على كلمة Alice في أي مجال
التطبيق \ كتاب :: بحث ( 'أليس') -> لقطة (20) -> الحصول على ()

أنا متأكد من أنك ستحصل على بعض النتائج ، لأن طريقة Faker \ Generator :: realText تُرجع نصًا عشوائيًا من كتاب Alice in a Wonderland.

لم نخبر Elasticsearch بالمجالات التي لها أولوية أكبر ، ولهذا السبب يمكننا رؤية فوضى في النتيجة. سيكون من الجميل أن يكون لديك سجلات مع Alice في العنوان في الأعلى والتسجيلات مع Alice في الوصف في الأسفل. ولكن كيف يمكننا تحقيق هذا؟ الجواب هو قاعدة البحث.

لراحتك ، هناك أمر لإنشاء قاعدة البحث:

جعل الحرفيين php: البحث عن القاعدة BookSearchRule

قاعدة البحث عبارة عن فصل ، يصف كيفية إجراء استعلام البحث. يجب عليك تطبيق طريقة واحدة فقط - buildQueryPayload. يجب أن تقوم هذه الطريقة بإرجاع استعلام منطقي.

نريد البحث حسب العنوان والوصف في الوقت الحالي ، لذلك دعونا نقوم بتعديل فئة BookSearchRule وفقًا لاحتياجاتنا:

<؟ PHP
مساحة التطبيق
استخدام ScoutElastic \ SearchRule؛
الطبقة BookSearchRule يمتد SearchRule
{
    بناء الوظيفة العامة QueryPayload ()
    {
        $ query = $ this-> builder-> query؛
        إرجاع [
            'should' => [
                [
                    'تطابق' => [
                        'title' => [
                            'query' => $ query ،
                            'دفعة' => 2
                        ]
                    ]
                ]،
                [
                    'تطابق' => [
                        "الوصف" => [
                            'query' => $ query ،
                            'دفعة' => 1
                        ]
                    ]
                ]
            ]
        ].
    }
}

الآن دعنا نطلب من نموذج الكتاب استخدام قاعدة البحث الجديدة افتراضيًا:

<؟ PHP
// ...
كتاب الطبقة يمتد SearchableModel
{
    searchRules $ المحمي = [
        BookSearchRule :: الفئة
    ].
    / ...
}

دعنا نجعل نفس الاستعلام مرة أخرى:

التطبيق \ كتاب :: بحث ( 'أليس') -> لقطة (20) -> الحصول على ()

يمكنك رؤية نتيجة مختلفة الآن: السجلات مع Alice في العنوان في الأعلى. وهذا هو بالضبط ما أردنا.

حسنًا ، دعنا ننتقل إلى المثال التالي. ماذا لو أردنا الحصول على جميع الكتب التي كتبت بعد عام 2010؟ ليس هناك أى مشكلة! يمكننا أن نفعل ذلك مثل هذا:

// نقول Elasticsearch - العثور على كل ما تم إصداره بعد عام 2010
App \ Book :: search ('*') -> حيث ('year'، '>'، 2010) -> take (10) -> get ()

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

يمكننا تحديد طريقة toSearchableArray لتحديد الحقول التي يجب فهرستها بواسطة Elasticsearch:

<؟ PHP
// ...
كتاب الطبقة يمتد SearchableModel
{
    // ...
    الوظيفة العامة toSearchableArray ()
    {
        إرجاع array_merge (
            / / افتراضيًا ، سيتم فهرسة جميع حقول النماذج
            الأم :: toSearchableArray ()
            ['author_name' => $ this-> author-> name]
        )؛
    }
}

الآن يتعين علينا إضافة author_name إلى تعيين النموذج:

<؟ PHP
// ...
كتاب الطبقة يمتد SearchableModel
{
    // ...
    تعيين $ المحمية = [
        'الخصائص' => [
            'id' => [
                "اكتب" => "عدد صحيح" ،
                'index' => 'not_analyzed'
            ]،
            'title' => [
                'type' => 'string' ،
                "محلل" => "الإنجليزية"
            ]،
            "الوصف" => [
                'type' => 'string' ،
                "محلل" => "الإنجليزية"
            ]،
            'السنة' => [
                "اكتب" => "عدد صحيح" ،
                'index' => 'not_analyzed'
            ]،
            'author_id' => [
                "اكتب" => "عدد صحيح" ،
                'index' => 'not_analyzed'
            ]،
            'author_name' => [
                'type' => 'string' ،
                "محلل" => "الإنجليزية"
            ]
        ]
    ].
    // ...
}

شيء واحد آخر ، يجب علينا تعديل قاعدة البحث:

<؟ PHP
مساحة التطبيق
استخدام ScoutElastic \ SearchRule؛
الطبقة BookSearchRule يمتد SearchRule
{
    بناء الوظيفة العامة QueryPayload ()
    {
        $ query = $ this-> builder-> query؛
        إرجاع [
            'should' => [
                [
                    'تطابق' => [
                        'title' => [
                            'query' => $ query ،
                            'دفعة' => 3
                        ]
                    ]
                ]،
                [
                    'تطابق' => [
                        'author_name' => [
                            'query' => $ query ،
                            'دفعة' => 2
                        ]
                    ]
                ]،
                [
                    'تطابق' => [
                        "الوصف" => [
                            'query' => $ query ،
                            'دفعة' => 1
                        ]
                    ]
                ]
            ]
        ].
    }
}

نحن الآن على استعداد للبحث عن طريق حقل جديد ، لكن لم تتم فهرسته: لم يكن Elasticsearch يعرف أي شيء عن هذا الحقل عندما كنا نقوم بإنشاء بيانات مزيفة. لحسن الحظ ، يمكننا إعادة فحص البيانات باستخدام أمر الاستيراد:

الحرفيين php الكشفية: استيراد "التطبيق \ كتاب"

خذ اسم المؤلف الأول من قاعدة البيانات:

التطبيق \ الكاتب :: أولا () -> اسم

في حالتي ، إنها روكسان بوهم. دعنا نحاول العثور على كتب روكسان:

App \ Book :: search ('Roxanne Boehm') -> get ()

إنها تعمل!

Afterwords

إذا كنت ترغب في الحصول على مزيد من المعلومات حول إمكانيات Laravel Scout ، فتحقق من الوثائق الرسمية وصفحة سائق Elasticsearch على جيثب.

إذا كان لديك أي أسئلة أو كنت بحاجة إلى مساعدة فلا تتردد في ترك تعليق أدناه.

شكرا للجميع على ملاحظاتك! لقد قمت بتغيير جزء تثبيت Elasticsearch لتزويدك بخطوات التثبيت لأحدث إصدار. لقد قمت أيضًا بإصلاح بعض الأخطاء في المقالة وأصدرت الإصدار الجديد من برنامج Scout Driver باستخدام استعلام match_all ثابت.