اخبار منصات الأفلام

عكس البحث في الرسم البياني الموحد لـ Netflix


مدونة نيتفليكس التقنية

بقلم ريكي جاردينر وأليكس هوتر وكاتي لوفيفر

منذ منشوراتنا السابقة المتعلقة بدور هندسة المحتوى في تمكين وظيفة البحث ضمن الرسم البياني الموحد لـ Netflix (المقالة الأولى، حيث نحدد المشكلة ونوضح بنية الفهرسة بالتفصيل، والمقالة الثانية، حيث نوضح بالتفصيل كيفية تسهيل الاستعلام) كانت هناك تغييرات كبيرة التطورات. لقد فتحنا Studio Search خارج نطاق هندسة المحتوى ليشمل المؤسسة الهندسية بأكملها في Netflix وأعدنا تسميته Graph Search. هناك أكثر من 100 تطبيق متكامل مع Graph Search وما يقرب من 50 مؤشرًا ندعمها. نواصل إضافة وظائف إلى الخدمة. كما وعدنا في المنشور السابق، سنشارك كيف عقدنا شراكة مع أحد فرق هندسة الاستوديو لدينا لإنشاء بحث عكسي. يعكس البحث العكسي نمط الاستعلام القياسي: فبدلاً من البحث عن المستندات التي تطابق الاستعلام، فإنه يبحث عن الاستعلامات التي تطابق مستندًا.

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

لذلك تشترك Tiffany في الإشعارات وتحديثات التقويم الخاصة بمجالات معينة من الاهتمام، مثل “الأفلام التي يتم تصويرها في مكسيكو سيتي والتي ليس لها دور رئيسي معين”، أو “الأفلام المعرضة لخطر عدم الاستعداد بحلول تاريخ إطلاقها”.

لا تشترك Tiffany في تحديثات أفلام معينة، ولكنها تشترك في الاستعلامات التي تعرض مجموعة فرعية ديناميكية من الأفلام. وهذا يشكل مشكلة بالنسبة لنا المسؤولين عن إرسال تلك الإخطارات لها. عندما يتغير فيلم ما، لا نعرف من يجب إبلاغه، نظرًا لعدم وجود ارتباط بين الموظفين والأفلام التي تهمهم.

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

إذا تمكنا من الإجابة على السؤال “هل سيتم إرجاع هذا الفيلم من خلال هذا الاستعلام”، فيمكننا إعادة الاستعلام بناءً على أحداث التغيير بدقة الليزر وعدم التأثير على النظام البيئي الأوسع.

تم إنشاء Graph Search على رأس Elasticsearch، الذي يتمتع بالإمكانيات الدقيقة التي نحتاجها:

بدلاً من إجراء بحث (مثل “أفلام باللغة الإسبانية تم تصويرها في مكسيكو سيتي”) وإرجاع المستندات المطابقة (واحد للغجر، وواحد لفاميليا)، يأخذ الاستعلام المتنقل مستندًا (واحد للغجر) ويعيد عمليات البحث التي مطابقة هذا المستند، مثل “الأفلام باللغة الإسبانية” و”الأعمال الدرامية المكتوبة”.

لقد قمنا بتوصيل هذه الوظيفة على أنها القدرة على حفظ البحث، والتي تسمى SavedSearches، وهو عامل تصفية مستمر على فهرس موجود.

type SavedSearch {
id: ID!
filter: String
index: SearchIndex!
}

يتم تحويل هذا المرشح، المكتوب في Graph Search DSL، إلى استعلام Elasticsearch ويتم فهرسته في حقل الدورق. لمعرفة المزيد حول Graph Search DSL وسبب إنشائنا له بدلاً من استخدام لغة استعلام Elasticsearch مباشرة، راجع قسم لغة الاستعلام في “كيف تجعل هندسة محتوى Netflix الرسم البياني الموحد قابلاً للبحث (الجزء 2)”.

لقد أطلقنا على عملية البحث عن عمليات البحث المحفوظة المطابقة ReverseSearch. هذا هو الجزء الأكثر مباشرة من هذا العرض. أضفنا محللًا جديدًا إلى خدمة الرسم البياني للمجال (DGS) لبحث الرسم البياني. يأخذ فهرس الاهتمام والمستند، ويعيد جميع عمليات البحث المحفوظة التي تطابق المستند عن طريق إصدار استعلام ترشيح.

"""
Query for retrieving all the registered saved searches, in a given index,
based on a provided document. The document in this case is an ElasticSearch
document that is generated based on the configuration of the index.
"""
reverseSearch(
after: String,
document: JSON!,
first: Int!,
index: SearchIndex!): SavedSearchConnection

إصرار أ SavedSearch يتم تنفيذه كطفرة جديدة في Graph Search DGS. يؤدي هذا في النهاية إلى تشغيل فهرسة استعلام Elasticsearch في حقل الدورق.

"""
Mutation for registering and updating a saved search. They need to be updated
any time a user adjusts their search criteria.
"""
upsertSavedSearch(input: UpsertSavedSearchInput!): UpsertSavedSearchPayload

أدى دعم حقول الدورق إلى تغيير جذري في كيفية توفير مسارات الفهرسة لبحث الرسم البياني (راجع قسم البنية في كيفية قيام Netflix Content Engineering بجعل الرسم البياني الموحد قابلاً للبحث). بدلاً من وجود مسار فهرسة واحد لكل فهرس Graph Search، أصبح لدينا الآن مساران: أحدهما لفهرسة المستندات والآخر لفهرسة عمليات البحث المحفوظة في فهرس ترشيح. لقد اخترنا إضافة حقول الدورق إلى فهرس منفصل من أجل ضبط الأداء لنوعي الاستعلامات بشكل منفصل.

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

مثال لتعيين فهرس الوثيقة

نمط الفهرس — application_*

{
"order": 1,
"index_patterns": ["application_*"],
"mappings": {
"properties": {
"movieTitle": {
"type": "keyword"
},
"isArchived": {
"type": "boolean"
}
}
}

مثال على تعيينات الفهرس المتسرب

نمط الفهرس — *_percolate

{
"order": 2,
"index_patterns": ["*_percolate*"],
"mappings": {
"properties": {
"percolate_query": {
"type": "percolator"
}
}
}
}

مثال على رسم الخرائط التي تم إنشاؤها

اسم فهرس الترشيح هو application_v1_percolate

{
"application_v1_percolate": {
"mappings": {
"_doc": {
"properties": {
"movieTitle": {
"type": "keyword"
},
"isArchived": {
"type": "boolean"
},
"percolate_query": {
"type": "percolator"
}
}
}
}
}
}

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

يرى Data Mesh — منصة لنقل ومعالجة البيانات @ Netflix لمعرفة المزيد حول Data Mesh.
  1. متى SavedSearches تم تعديلها، ونخزنها في CockroachDB الخاص بنا، ويصدر الرابط المصدر لقاعدة بيانات Cockroach أحداث CDC.
  2. تتم مشاركة جدول واحد لتخزين الجميع SavedSearches، لذا فإن الخطوة التالية هي التصفية وصولاً إلى تلك المخصصة لهذا الفهرس فقط باستخدام معالج التصفية.
  3. كما ذكرنا سابقًا، ما يتم تخزينه في قاعدة البيانات هو مرشح Graph Search المخصص لدينا DSL، وهو يختلف عن Elasticsearch DSL، لذلك لا يمكننا فهرسة الحدث مباشرة إلى فهرس الترشيح. بدلاً من ذلك، قمنا بإصدار طفرة إلى Graph Search DGS. يقوم Graph Search DGS بترجمة DSL إلى استعلام Elasticsearch.
  4. ثم نقوم بفهرسة استعلام Elasticsearch كحقل ترشيح في فهرس الترشيح المناسب.
  5. نجاح أو فشل فهرسة SavedSearch يتم إرجاع. على الفشل، SavedSearch يتم إرسال الأحداث إلى قائمة انتظار الرسائل الميتة (DLQ) التي يمكن استخدامها لمعالجة أي فشل، مثل إزالة الحقول المشار إليها في استعلام البحث من الفهرس.

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

داليا وفوريست من سلسلة Baby Animal Cam

عند إجراء تغيير على تعريف الفهرس الذي يتطلب تعيينًا جديدًا، كما هو الحال عندما نضيف علامة الحيوان، يقوم Graph Search بإنشاء إصدار جديد من فهرس Elasticsearch ومسار جديد لملءه. يقرأ خط الأنابيب الجديد هذا من موضوع كافكا المضغوط بالسجل في Data Mesh – وهذه هي الطريقة التي يمكننا من خلالها إعادة فهرسة المجموعة بأكملها دون مطالبة مصادر البيانات بإعادة إرسال جميع الأحداث القديمة. يعمل المسار الجديد وخط الأنابيب القديم جنبًا إلى جنب، حتى يقوم المسار الجديد بمعالجة الأعمال المتراكمة، وعند هذه النقطة ينتقل Graph Search إلى الإصدار باستخدام الأسماء المستعارة لفهرس Elasticsearch.

إن إنشاء فهرس جديد لمستنداتنا يعني أننا بحاجة أيضًا إلى إنشاء فهرس ترشيحي جديد لاستعلاماتنا حتى تتمكن من الحصول على تعيينات فهرس متسقة. يحتاج هذا الفهرس الترشيحي الجديد أيضًا إلى إعادة ملئه عندما نغير الإصدارات. ولهذا السبب يعمل المسار بالطريقة التي يعمل بها – يمكننا مرة أخرى استخدام موضوعات السجل المضغوطة في Data Mesh لإعادة فهرسة مجموعة البيانات SavedSearches عندما نقوم بتدوير خط أنابيب فهرسة جديد.

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

كنا نأمل أن تكون وظيفة البحث العكسي مفيدة في النهاية للفرق الهندسية الأخرى. لقد تم التعامل معنا على الفور تقريبًا مع مشكلة يمكن أن يحلها البحث العكسي.

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

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

تبدو عمليات البحث العكسي أيضًا بمثابة أساس واعد لإنشاء واجهات مستخدم أكثر استجابة. بدلاً من جلب النتائج مرة واحدة كاستعلام، يمكن توفير نتائج البحث عبر اشتراك GraphQL. يمكن ربط هذه الاشتراكات بـ SavedSearch ومع حدوث تغييرات في الفهرس، يمكن استخدام البحث العكسي لتحديد متى يتم تحديث مجموعة المفاتيح التي يتم إرجاعها بواسطة الاشتراك.

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *

زر الذهاب إلى الأعلى