یک اتصال دهنده محتوا ایجاد کنید

رابط محتوا یک برنامه نرم‌افزاری است که برای پیمایش داده‌ها در مخزن یک سازمان و پر کردن یک منبع داده استفاده می‌شود. گوگل گزینه‌های زیر را برای توسعه رابط‌های محتوا ارائه می‌دهد:

  • کیت توسعه نرم‌افزار رابط محتوا (Content Connector SDK). اگر با جاوا برنامه‌نویسی می‌کنید، این گزینه خوبی است. کیت توسعه نرم‌افزار رابط محتوا (Content Connector SDK) یک پوشش پیرامون REST API است که به شما امکان می‌دهد به سرعت رابط‌ها را ایجاد کنید. برای ایجاد یک رابط محتوا با استفاده از SDK، به بخش «ایجاد یک رابط محتوا با استفاده از SDK رابط محتوا » مراجعه کنید.

  • یک API سطح پایین REST یا کتابخانه‌های API. اگر با جاوا برنامه‌نویسی نمی‌کنید یا اگر کدبیس شما با یک API REST یا یک کتابخانه سازگارتر است، از این گزینه‌ها استفاده کنید. برای ایجاد یک رابط محتوا با استفاده از REST API، به بخش «ایجاد یک رابط محتوا با استفاده از REST API» مراجعه کنید.

یک رابط محتوای معمولی وظایف زیر را انجام می‌دهد:

  1. پارامترهای پیکربندی را می‌خواند و پردازش می‌کند.
  2. تکه‌های گسسته‌ای از داده‌های قابل فهرست‌بندی، به نام " آیتم‌ها "، را از مخزن محتوای شخص ثالث دریافت می‌کند.
  3. ACLها، فراداده‌ها و داده‌های محتوا را در آیتم‌های قابل فهرست‌بندی ترکیب می‌کند.
  4. آیتم‌ها را در منبع داده Cloud Search فهرست‌بندی می‌کند.
  5. (اختیاری) به اعلان‌های تغییر از مخزن محتوای شخص ثالث گوش می‌دهد. اعلان‌های تغییر به درخواست‌های نمایه‌سازی تبدیل می‌شوند تا منبع داده Cloud Search با مخزن شخص ثالث همگام بماند. رابط فقط در صورتی این کار را انجام می‌دهد که مخزن از تشخیص تغییر پشتیبانی کند.

با استفاده از کیت توسعه نرم‌افزاری رابط محتوا (Content Connector SDK)، یک رابط محتوا (content connector) ایجاد کنید.

بخش‌های زیر نحوه ایجاد یک رابط محتوا با استفاده از کیت توسعه نرم‌افزار رابط محتوا (Content Connector SDK) را توضیح می‌دهند.

وابستگی‌ها را تنظیم کنید

برای استفاده از SDK باید وابستگی‌های خاصی را در فایل ساخت خود لحاظ کنید. برای مشاهده وابستگی‌های محیط ساخت خود، روی تب زیر کلیک کنید:

ماون

<dependency>
<groupId>com.google.enterprise.cloudsearch</groupId>
<artifactId>google-cloudsearch-indexing-connector-sdk</artifactId>
<version>v1-0.0.3</version>
</dependency>

گرادل

compile group: 'com.google.enterprise.cloudsearch',
        name: 'google-cloudsearch-indexing-connector-sdk',
        version: 'v1-0.0.3'

پیکربندی کانکتور خود را ایجاد کنید

هر کانکتور یک فایل پیکربندی دارد که شامل پارامترهای مورد استفاده کانکتور، مانند شناسه مخزن شما، است. پارامترها به صورت جفت‌های کلید-مقدار تعریف می‌شوند، مانند api.sourceId= 1234567890abcdef .

کیت توسعه نرم‌افزار جستجوی ابری گوگل (Google Cloud Search SDK) شامل چندین پارامتر پیکربندی ارائه شده توسط گوگل است که توسط همه کانکتورها استفاده می‌شود. شما باید پارامترهای ارائه شده توسط گوگل زیر را در فایل پیکربندی خود اعلام کنید:

  • برای یک رابط محتوا، باید api.sourceId و api.serviceAccountPrivateKeyFile را تعریف کنید، زیرا این پارامترها محل مخزن شما و کلید خصوصی مورد نیاز برای دسترسی به مخزن را مشخص می‌کنند.
  • برای یک رابط هویت، باید api.identitySourceId تعریف کنید زیرا این پارامتر محل منبع هویت خارجی شما را مشخص می‌کند. اگر کاربران را همگام‌سازی می‌کنید، باید api.customerId نیز به عنوان شناسه منحصر به فرد برای حساب Google Workspace شرکت خود تعریف کنید.

مگر اینکه بخواهید مقادیر پیش‌فرض سایر پارامترهای ارائه شده توسط گوگل را لغو کنید، نیازی به اعلام آنها در فایل پیکربندی خود ندارید. برای اطلاعات بیشتر در مورد پارامترهای پیکربندی ارائه شده توسط گوگل، مانند نحوه تولید شناسه‌ها و کلیدهای خاص، به پارامترهای پیکربندی ارائه شده توسط گوگل مراجعه کنید.

همچنین می‌توانید پارامترهای مختص مخزن خود را برای استفاده در فایل پیکربندی خود تعریف کنید.

فایل پیکربندی را به کانکتور ارسال کنید

ویژگی config سیستم را طوری تنظیم کنید که فایل پیکربندی را به کانکتور شما منتقل کند. می‌توانید این ویژگی را با استفاده از آرگومان -D هنگام شروع کانکتور تنظیم کنید. برای مثال، دستور زیر کانکتور را با فایل پیکربندی MyConfig.properties شروع می‌کند:

java -classpath myconnector.jar;... -Dconfig=MyConfig.properties MyConnector

اگر این آرگومان وجود نداشته باشد، SDK تلاش می‌کند به یک فایل پیکربندی پیش‌فرض با نام connector-config.properties دسترسی پیدا کند.

استراتژی پیمایش خود را تعیین کنید

وظیفه اصلی یک رابط محتوا، پیمایش یک مخزن و فهرست‌بندی داده‌های آن است. شما باید یک استراتژی پیمایش را بر اساس اندازه و چیدمان داده‌های موجود در مخزن خود پیاده‌سازی کنید. می‌توانید استراتژی خود را طراحی کنید یا از بین استراتژی‌های زیر که در SDK پیاده‌سازی شده‌اند، انتخاب کنید:

استراتژی پیمایش کامل

یک استراتژی پیمایش کامل، کل مخزن را اسکن می‌کند و هر آیتم را کورکورانه فهرست‌بندی می‌کند. این استراتژی معمولاً زمانی استفاده می‌شود که مخزن کوچکی دارید و می‌توانید از پس هزینه‌های سربار انجام یک پیمایش کامل در هر بار فهرست‌بندی برآیید.

این استراتژی پیمایش برای مخازن کوچک با داده‌های عمدتاً ایستا و غیرسلسله مراتبی مناسب است. همچنین می‌توانید از این استراتژی پیمایش زمانی استفاده کنید که تشخیص تغییر دشوار است یا توسط مخزن پشتیبانی نمی‌شود.

استراتژی پیمایش لیست

یک استراتژی پیمایش لیست، کل مخزن، شامل تمام گره‌های فرزند را اسکن می‌کند و وضعیت هر آیتم را تعیین می‌کند. سپس، رابط یک گذر دوم را انجام می‌دهد و فقط آیتم‌هایی را که جدید هستند یا از آخرین نمایه‌سازی به‌روزرسانی شده‌اند، فهرست‌بندی می‌کند. این استراتژی معمولاً برای انجام به‌روزرسانی‌های افزایشی در یک فهرست موجود استفاده می‌شود (به جای اینکه مجبور باشید هر بار که فهرست را به‌روزرسانی می‌کنید، یک پیمایش کامل انجام دهید).

این استراتژی پیمایش زمانی مناسب است که تشخیص تغییرات دشوار باشد یا توسط مخزن پشتیبانی نشود، داده‌های غیرسلسله مراتبی داشته باشید و با مجموعه داده‌های بسیار بزرگی کار کنید.

پیمایش گراف

یک استراتژی پیمایش گراف، کل گره والد را اسکن می‌کند و وضعیت هر آیتم را مشخص می‌کند. سپس، رابط یک گذر دوم انجام می‌دهد و فقط آیتم‌های موجود در گره ریشه را که جدید هستند یا از آخرین فهرست‌بندی به‌روزرسانی شده‌اند، فهرست‌بندی می‌کند. در نهایت، رابط هر شناسه فرزند را ارسال می‌کند و سپس آیتم‌های موجود در گره‌های فرزند را که جدید هستند یا به‌روزرسانی شده‌اند، فهرست‌بندی می‌کند. رابط به صورت بازگشتی از طریق تمام گره‌های فرزند ادامه می‌دهد تا زمانی که همه آیتم‌ها آدرس‌دهی شوند. چنین پیمایشی معمولاً برای مخازن سلسله مراتبی استفاده می‌شود که در آن‌ها فهرست کردن همه شناسه‌ها عملی نیست.

این استراتژی در صورتی مناسب است که داده‌های سلسله مراتبی دارید که نیاز به خزش دارند، مانند مجموعه‌ای از دایرکتوری‌ها یا صفحات وب.

هر یک از این استراتژی‌های پیمایش توسط یک کلاس رابط قالب در SDK پیاده‌سازی شده است. در حالی که می‌توانید استراتژی پیمایش خود را پیاده‌سازی کنید، این قالب‌ها سرعت توسعه رابط شما را تا حد زیادی افزایش می‌دهند. برای ایجاد یک رابط با استفاده از یک الگو، به بخش مربوط به استراتژی پیمایش خود بروید:

با استفاده از یک کلاس الگو، یک رابط پیمایش کامل ایجاد کنید

این بخش از مستندات به قطعه کدهایی از مثال FullTraversalSample اشاره دارد.

نقطه ورود کانکتور را پیاده‌سازی کنید

نقطه ورود به یک کانکتور، متد main() است. وظیفه اصلی این متد ایجاد یک نمونه از کلاس Application و فراخوانی متد start() آن برای اجرای کانکتور است.

قبل از فراخوانی application.start() ، از کلاس IndexingApplication.Builder برای نمونه‌سازی الگوی FullTraversalConnector استفاده کنید. FullTraversalConnector یک شیء Repository را می‌پذیرد که متدهای آن را پیاده‌سازی می‌کنید. قطعه کد زیر نحوه پیاده‌سازی متد main() را نشان می‌دهد:

نمونه پیمایش کامل.java
/**
 * This sample connector uses the Cloud Search SDK template class for a full
 * traversal connector.
 *
 * @param args program command line arguments
 * @throws InterruptedException thrown if an abort is issued during initialization
 */
public static void main(String[] args) throws InterruptedException {
  Repository repository = new SampleRepository();
  IndexingConnector connector = new FullTraversalConnector(repository);
  IndexingApplication application = new IndexingApplication.Builder(connector, args).build();
  application.start();
}

در پشت صحنه، SDK متد initConfig() را پس از فراخوانی Application.build توسط متد main() کانکتور شما، فراخوانی می‌کند. متد initConfig() وظایف زیر را انجام می‌دهد:

  1. متد Configuation.isInitialized() را فراخوانی می‌کند تا مطمئن شود که Configuration مقداردهی اولیه نشده است.
  2. یک شیء Configuration را با جفت‌های کلید-مقدار ارائه شده توسط گوگل مقداردهی اولیه می‌کند. هر جفت کلید-مقدار در یک شیء ConfigValue درون شیء Configuration ذخیره می‌شود.

پیاده‌سازی رابط Repository )

تنها هدف شیء Repository انجام پیمایش و فهرست‌بندی اقلام مخزن است. هنگام استفاده از یک الگو، برای ایجاد یک رابط محتوا، فقط باید متدهای خاصی را در رابط Repository بازنویسی کنید. متدهایی که شما بازنویسی می‌کنید به الگو و استراتژی پیمایشی که استفاده می‌کنید بستگی دارد. برای FullTraversalConnector ، متدهای زیر را بازنویسی کنید:

  • متد init() . برای انجام هرگونه تنظیم و مقداردهی اولیه مخزن داده، متد init() را بازنویسی کنید.

  • متد getAllDocs() . برای پیمایش و فهرست‌بندی تمام آیتم‌های موجود در مخزن داده‌ها، متد getAllDocs() را بازنویسی کنید. این متد برای هر پیمایش زمان‌بندی‌شده (مطابق با پیکربندی شما) یک بار فراخوانی می‌شود.

  • (اختیاری) متد getChanges() . اگر مخزن شما از تشخیص تغییر پشتیبانی می‌کند، متد getChanges() را بازنویسی کنید. این متد برای هر پیمایش افزایشی برنامه‌ریزی‌شده (مطابق با پیکربندی شما) یک بار فراخوانی می‌شود تا موارد تغییر یافته را بازیابی و فهرست‌بندی کند.

  • (اختیاری) متد close() . اگر نیاز به پاکسازی مخزن دارید، متد close() را بازنویسی کنید. این متد یک بار در هنگام خاموش شدن کانکتور فراخوانی می‌شود.

هر یک از متدهای شیء Repository نوعی از شیء ApiOperation را برمی‌گرداند. یک شیء ApiOperation عملی را به شکل یک یا شاید چندین فراخوانی IndexingService.indexItem() برای انجام فهرست‌بندی واقعی مخزن شما انجام می‌دهد.

دریافت پارامترهای پیکربندی سفارشی

به عنوان بخشی از مدیریت پیکربندی کانکتور، شما نیاز به دریافت پارامترهای سفارشی از شیء Configuration خواهید داشت. این کار معمولاً در متد init() کلاس Repository انجام می‌شود.

کلاس Configuration متدهای مختلفی برای دریافت انواع داده‌های مختلف از یک پیکربندی دارد. هر متد یک شیء ConfigValue را برمی‌گرداند. سپس از متد get() شیء ConfigValue برای بازیابی مقدار واقعی استفاده خواهید کرد. قطعه کد زیر، از FullTraversalSample ، نحوه بازیابی یک مقدار صحیح سفارشی از یک شیء Configuration را نشان می‌دهد:

نمونه پیمایش کامل.java
@Override
public void init(RepositoryContext context) {
  log.info("Initializing repository");
  numberOfDocuments = Configuration.getInteger("sample.documentCount", 10).get();
}

برای دریافت و تجزیه یک پارامتر حاوی چندین مقدار، از یکی از تجزیه‌کننده‌های نوع کلاس Configuration برای تجزیه داده‌ها به تکه‌های گسسته استفاده کنید. قطعه کد زیر، از رابط آموزشی، از متد getMultiValue برای دریافت لیستی از نام‌های مخزن GitHub استفاده می‌کند:

مخزن گیت‌هاب.جاوا
ConfigValue<List<String>> repos = Configuration.getMultiValue(
    "github.repos",
    Collections.emptyList(),
    Configuration.STRING_PARSER);

انجام پیمایش کامل

برای انجام یک پیمایش کامل و فهرست‌بندی مخزن خود، تابع getAllDocs() را نادیده بگیرید. متد getAllDocs() یک نقطه بررسی (checkpoint) می‌پذیرد. این نقطه بررسی برای از سرگیری فهرست‌بندی در یک مورد خاص در صورت قطع شدن فرآیند استفاده می‌شود. برای هر مورد در مخزن خود، این مراحل را در متد getAllDocs() انجام دهید:

  1. مجوزها را تنظیم کنید.
  2. متادیتا (فراداده) را برای موردی که در حال فهرست‌بندی آن هستید، تنظیم کنید.
  3. متادیتا و آیتم را در یک RepositoryDoc قابل فهرست‌بندی ترکیب کنید.
  4. هر آیتم قابل ایندکس را در یک تکرارکننده که توسط متد getAllDocs() برگردانده می‌شود، بسته‌بندی کنید. توجه داشته باشید که getAllDocs() در واقع یک CheckpointCloseableIterable برمی‌گرداند که یک تکرار از اشیاء ApiOperation است و هر شیء نشان‌دهنده یک درخواست API است که روی RepositoryDoc انجام می‌شود، مانند ایندکس کردن آن.

اگر مجموعه آیتم‌ها برای پردازش در یک فراخوانی واحد بسیار بزرگ است، یک Checkpoint اضافه کنید و hasMore(true) را برای نشان دادن اینکه آیتم‌های بیشتری برای اندیس‌گذاری در دسترس هستند، تنظیم کنید.

تنظیم مجوزها برای یک مورد

مخزن شما از یک فهرست کنترل دسترسی (ACL) برای شناسایی کاربران یا گروه‌هایی که به یک مورد دسترسی دارند استفاده می‌کند. ACL فهرستی از شناسه‌ها برای گروه‌ها یا کاربرانی است که می‌توانند به آن مورد دسترسی داشته باشند.

شما باید ACL مورد استفاده توسط مخزن خود را کپی کنید تا مطمئن شوید فقط کاربرانی که به یک مورد دسترسی دارند می‌توانند آن مورد را در نتیجه جستجو مشاهده کنند. ACL مربوط به یک مورد باید هنگام فهرست‌بندی یک مورد لحاظ شود تا جستجوی ابری گوگل اطلاعات لازم برای ارائه سطح صحیح دسترسی به آن مورد را داشته باشد.

کیت توسعه نرم‌افزار رابط محتوا (Content Connector SDK) مجموعه‌ای غنی از کلاس‌ها و روش‌های ACL را برای مدل‌سازی ACLهای اکثر مخازن ارائه می‌دهد. شما باید ACL هر آیتم موجود در مخزن خود را تجزیه و تحلیل کنید و هنگام فهرست‌بندی یک آیتم، یک ACL متناظر برای جستجوی ابری گوگل (Google Cloud Search) ایجاد کنید. اگر ACL مخزن شما از مفاهیمی مانند وراثت ACL استفاده می‌کند، مدل‌سازی آن ACL می‌تواند دشوار باشد. برای اطلاعات بیشتر در مورد ACLهای جستجوی ابری گوگل، به ACLهای جستجوی ابری گوگل (Google Cloud Search ACLs) مراجعه کنید.

نکته: API نمایه‌سازی جستجوی ابری از ACLهای تک دامنه‌ای پشتیبانی می‌کند. از ACLهای بین دامنه‌ای پشتیبانی نمی‌کند. از کلاس Acl.Builder برای تنظیم دسترسی به هر آیتم با استفاده از ACL استفاده کنید. قطعه کد زیر که از نمونه کامل پیمایش گرفته شده است، به همه کاربران یا «مدیران» ( getCustomerPrincipal() ) اجازه می‌دهد هنگام انجام جستجو، «خواننده» همه آیتم‌ها ( .setReaders() ) باشند.

نمونه پیمایش کامل.java
// Make the document publicly readable within the domain
Acl acl = new Acl.Builder()
    .setReaders(Collections.singletonList(Acl.getCustomerPrincipal()))
    .build();

برای مدل‌سازی صحیح ACLها برای مخزن، باید ACLها را درک کنید. به عنوان مثال، ممکن است در حال فهرست‌بندی فایل‌ها در یک سیستم فایل باشید که از نوعی مدل وراثت استفاده می‌کند که در آن پوشه‌های فرزند، مجوزها را از پوشه‌های والد به ارث می‌برند. مدل‌سازی وراثت ACL نیاز به اطلاعات اضافی دارد که در ACLهای جستجوی ابری گوگل پوشش داده شده است.

تنظیم فراداده برای یک آیتم

متادیتا در یک شیء Item ذخیره می‌شود. برای ایجاد یک Item ، حداقل به یک رشته منحصر به فرد به نام ID، نوع Item، ACL، URL و نسخه برای Item نیاز دارید. قطعه کد زیر نحوه ساخت یک Item با استفاده از کلاس کمکی IndexingItemBuilder را نشان می‌دهد.

نمونه پیمایش کامل.java
// Url is required. Use google.com as a placeholder for this sample.
String viewUrl = "https://www.google.com";

// Version is required, set to current timestamp.
byte[] version = Longs.toByteArray(System.currentTimeMillis());

// Using the SDK item builder class to create the document with appropriate attributes
// (this can be expanded to include metadata fields etc.)
Item item = IndexingItemBuilder.fromConfiguration(Integer.toString(id))
    .setItemType(IndexingItemBuilder.ItemType.CONTENT_ITEM)
    .setAcl(acl)
    .setSourceRepositoryUrl(IndexingItemBuilder.FieldOrValue.withValue(viewUrl))
    .setVersion(version)
    .build();

ایجاد آیتم قابل فهرست‌بندی

پس از تنظیم فراداده برای آیتم، می‌توانید آیتم قابل فهرست‌بندی واقعی را با استفاده از کلاس RepositoryDoc.Builder ایجاد کنید. مثال زیر نحوه ایجاد یک آیتم قابل فهرست‌بندی واحد را نشان می‌دهد.

نمونه پیمایش کامل.java
// For this sample, content is just plain text
String content = String.format("Hello world from sample doc %d", id);
ByteArrayContent byteContent = ByteArrayContent.fromString("text/plain", content);

// Create the fully formed document
RepositoryDoc doc = new RepositoryDoc.Builder()
    .setItem(item)
    .setContent(byteContent, IndexingService.ContentFormat.TEXT)
    .build();

یک RepositoryDoc نوعی از ApiOperation است که درخواست واقعی IndexingService.indexItem() را انجام می‌دهد.

همچنین می‌توانید از متد setRequestMode() از کلاس RepositoryDoc.Builder برای شناسایی درخواست ایندکس‌گذاری به عنوان ASYNCHRONOUS یا SYNCHRONOUS استفاده کنید:

ASYNCHRONOUS
حالت ناهمزمان منجر به تأخیر طولانی‌تر از زمان ایندکس‌گذاری تا ارائه سرویس می‌شود و سهمیه توان عملیاتی زیادی را برای درخواست‌های ایندکس‌گذاری در نظر می‌گیرد. حالت ناهمزمان برای ایندکس‌گذاری اولیه (backfill) کل مخزن توصیه می‌شود.
SYNCHRONOUS
حالت همگام منجر به کاهش تأخیر در نمایه‌سازی تا ارائه سرویس می‌شود و سهمیه توان عملیاتی محدودی را در خود جای می‌دهد. حالت همگام برای نمایه‌سازی به‌روزرسانی‌ها و تغییرات در مخزن توصیه می‌شود. در صورت عدم تعیین، حالت درخواست به طور پیش‌فرض روی SYNCHRONOUS تنظیم می‌شود.

هر آیتم قابل فهرست‌بندی را در یک تکرارکننده بسته‌بندی کنید

متد getAllDocs() یک Iterator ، به طور خاص یک CheckpointCloseableIterable ، از اشیاء RepositoryDoc را برمی‌گرداند. می‌توانید از کلاس CheckpointClosableIterableImpl.Builder برای ساخت و بازگرداندن یک iterator استفاده کنید. قطعه کد زیر نحوه ساخت و بازگرداندن یک iterator را نشان می‌دهد.

نمونه پیمایش کامل.java
CheckpointCloseableIterable<ApiOperation> iterator =
  new CheckpointCloseableIterableImpl.Builder<>(allDocs).build();

SDK هر فراخوانی اندیس‌گذاری که درون تکرارکننده قرار دارد را اجرا می‌کند.

مراحل بعدی

در اینجا چند گام بعدی که می‌توانید بردارید، آورده شده است:

با استفاده از یک کلاس الگو، یک رابط پیمایش لیست ایجاد کنید

صف نمایه‌سازی جستجوی ابری برای نگهداری شناسه‌ها و مقادیر هش اختیاری برای هر مورد در مخزن استفاده می‌شود. یک رابط پیمایش لیست، شناسه‌های مورد را به صف نمایه‌سازی جستجوی ابری گوگل (Google Cloud Search Indexing Queue) ارسال می‌کند و آنها را یکی یکی برای نمایه‌سازی بازیابی می‌کند. جستجوی ابری گوگل صف‌ها را نگهداری می‌کند و محتوای صف را برای تعیین وضعیت مورد، مانند اینکه آیا یک مورد از مخزن حذف شده است یا خیر، مقایسه می‌کند. برای اطلاعات بیشتر در مورد صف نمایه‌سازی جستجوی ابری، به صف نمایه‌سازی جستجوی ابری (The Cloud Search Indexing Queue) مراجعه کنید.

این بخش از مستندات به قطعه کدهایی از مثال ListTraversalSample اشاره دارد.

نقطه ورود کانکتور را پیاده‌سازی کنید

نقطه ورود به یک کانکتور، متد main() است. وظیفه اصلی این متد ایجاد یک نمونه از کلاس Application و فراخوانی متد start() آن برای اجرای کانکتور است.

قبل از فراخوانی application.start() ، از کلاس IndexingApplication.Builder برای نمونه‌سازی الگوی ListingConnector استفاده کنید. ListingConnector یک شیء Repository را می‌پذیرد که متدهای آن را پیاده‌سازی می‌کنید. قطعه کد زیر نحوه نمونه‌سازی ListingConnector و Repository مرتبط با آن را نشان می‌دهد:

نمونه پیمایش لیست.جاوا
/**
 * This sample connector uses the Cloud Search SDK template class for a
 * list traversal connector.
 *
 * @param args program command line arguments
 * @throws InterruptedException thrown if an abort is issued during initialization
 */
public static void main(String[] args) throws InterruptedException {
  Repository repository = new SampleRepository();
  IndexingConnector connector = new ListingConnector(repository);
  IndexingApplication application = new IndexingApplication.Builder(connector, args).build();
  application.start();
}

در پشت صحنه، SDK متد initConfig() را پس از فراخوانی Application.build توسط متد main() کانکتور شما، فراخوانی می‌کند. متد initConfig() به صورت زیر است:

  1. متد Configuation.isInitialized() را فراخوانی می‌کند تا مطمئن شود که Configuration مقداردهی اولیه نشده است.
  2. یک شیء Configuration را با جفت‌های کلید-مقدار ارائه شده توسط گوگل مقداردهی اولیه می‌کند. هر جفت کلید-مقدار در یک شیء ConfigValue درون شیء Configuration ذخیره می‌شود.

پیاده‌سازی رابط Repository )

تنها هدف شیء Repository انجام پیمایش و فهرست‌بندی اقلام مخزن است. هنگام استفاده از یک الگو، برای ایجاد یک رابط محتوا، فقط باید متدهای خاصی را در رابط Repository لغو کنید. متدهایی که شما لغو می‌کنید به الگو و استراتژی پیمایشی که استفاده می‌کنید بستگی دارد. برای ListingConnector ، متدهای زیر را لغو کنید:

  • متد init() . برای انجام هرگونه تنظیم و مقداردهی اولیه مخزن داده، متد init() را بازنویسی کنید.

  • متد getIds() . برای بازیابی شناسه‌ها و مقادیر هش برای همه رکوردهای موجود در مخزن، متد getIds() را بازنویسی کنید.

  • متد getDoc() . برای افزودن، به‌روزرسانی، تغییر یا حذف آیتم‌ها از اندیس، متد getDoc() را بازنویسی کنید.

  • (اختیاری) متد getChanges() . اگر مخزن شما از تشخیص تغییر پشتیبانی می‌کند، متد getChanges() را بازنویسی کنید. این متد برای هر پیمایش افزایشی برنامه‌ریزی‌شده (مطابق با پیکربندی شما) یک بار فراخوانی می‌شود تا موارد تغییر یافته را بازیابی و فهرست‌بندی کند.

  • (اختیاری) متد close() . اگر نیاز به پاکسازی مخزن دارید، متد close() را بازنویسی کنید. این متد یک بار در هنگام خاموش شدن کانکتور فراخوانی می‌شود.

هر یک از متدهای شیء Repository نوعی از شیء ApiOperation را برمی‌گرداند. یک شیء ApiOperation عملی را به شکل یک یا شاید چندین فراخوانی IndexingService.indexItem() برای انجام فهرست‌بندی واقعی مخزن شما انجام می‌دهد.

دریافت پارامترهای پیکربندی سفارشی

به عنوان بخشی از مدیریت پیکربندی کانکتور، شما نیاز به دریافت پارامترهای سفارشی از شیء Configuration خواهید داشت. این کار معمولاً در متد init() کلاس Repository انجام می‌شود.

کلاس Configuration متدهای مختلفی برای دریافت انواع داده‌های مختلف از یک پیکربندی دارد. هر متد یک شیء ConfigValue را برمی‌گرداند. سپس از متد get() شیء ConfigValue برای بازیابی مقدار واقعی استفاده خواهید کرد. قطعه کد زیر، از FullTraversalSample ، نحوه بازیابی یک مقدار صحیح سفارشی از یک شیء Configuration را نشان می‌دهد:

نمونه پیمایش کامل.java
@Override
public void init(RepositoryContext context) {
  log.info("Initializing repository");
  numberOfDocuments = Configuration.getInteger("sample.documentCount", 10).get();
}

برای دریافت و تجزیه یک پارامتر حاوی چندین مقدار، از یکی از تجزیه‌کننده‌های نوع کلاس Configuration برای تجزیه داده‌ها به تکه‌های گسسته استفاده کنید. قطعه کد زیر، از رابط آموزشی، از متد getMultiValue برای دریافت لیستی از نام‌های مخزن GitHub استفاده می‌کند:

مخزن گیت‌هاب.جاوا
ConfigValue<List<String>> repos = Configuration.getMultiValue(
    "github.repos",
    Collections.emptyList(),
    Configuration.STRING_PARSER);

پیمایش لیست را انجام دهید

متد getIds() را برای بازیابی شناسه‌ها و مقادیر هش برای همه رکوردهای موجود در مخزن، بازنویسی کنید. متد getIds() یک نقطه بررسی (checkpoint) می‌پذیرد. این نقطه بررسی برای از سرگیری فهرست‌بندی در یک مورد خاص در صورت قطع شدن فرآیند استفاده می‌شود.

در مرحله بعد، متد getDoc() را برای مدیریت هر آیتم در صف نمایه‌سازی جستجوی ابری، بازنویسی کنید.

شناسه‌های آیتم و مقادیر هش را فشار دهید

تابع getIds() را برای دریافت شناسه‌های آیتم‌ها و مقادیر هش محتوای مرتبط با آنها از مخزن، بازنویسی کنید. سپس جفت‌های شناسه و مقدار هش در درخواست عملیات ارسال به صف نمایه‌سازی جستجوی ابری بسته‌بندی می‌شوند. شناسه‌های ریشه یا والد معمولاً ابتدا و به دنبال آن شناسه‌های فرزند تا زمانی که کل سلسله مراتب آیتم‌ها پردازش شود، ارسال می‌شوند.

متد getIds() یک نقطه بررسی (checkpoint) را می‌پذیرد که نشان‌دهنده آخرین آیتمی است که باید ایندکس شود. این نقطه بررسی می‌تواند برای از سرگیری ایندکس‌گذاری در یک آیتم خاص در صورت قطع شدن فرآیند استفاده شود. برای هر آیتم در مخزن خود، این مراحل را در متد getIds() انجام دهید:

  • شناسه هر آیتم و مقدار هش مرتبط با آن را از مخزن دریافت کنید.
  • هر جفت شناسه و مقدار هش را در یک PushItems بسته‌بندی کنید.
  • هر PushItems در یک تکرارکننده که توسط متد getIds() برگردانده می‌شود، ترکیب کنید. توجه داشته باشید که getIds() در واقع یک CheckpointCloseableIterable برمی‌گرداند که یک تکرار از اشیاء ApiOperation است و هر شیء نشان‌دهنده یک درخواست API است که روی RepositoryDoc انجام می‌شود، مانند ارسال موارد به صف.

قطعه کد زیر نحوه دریافت شناسه و مقدار هش هر آیتم و درج آنها در PushItems را نشان می‌دهد. PushItems یک درخواست ApiOperation برای ارسال یک آیتم به صف نمایه‌سازی جستجوی ابری است.

نمونه پیمایش لیست.جاوا
PushItems.Builder allIds = new PushItems.Builder();
for (Map.Entry<Integer, Long> entry : this.documents.entrySet()) {
  String documentId = Integer.toString(entry.getKey());
  String hash = this.calculateMetadataHash(entry.getKey());
  PushItem item = new PushItem().setMetadataHash(hash);
  log.info("Pushing " + documentId);
  allIds.addPushItem(documentId, item);
}

قطعه کد زیر نحوه استفاده از کلاس PushItems.Builder را برای بسته‌بندی شناسه‌ها و مقادیر هش در یک ApiOperation نشان می‌دهد.

نمونه پیمایش لیست.جاوا
ApiOperation pushOperation = allIds.build();
CheckpointCloseableIterable<ApiOperation> iterator =
  new CheckpointCloseableIterableImpl.Builder<>(
      Collections.singletonList(pushOperation))
  .build();
return iterator;

موارد برای پردازش بیشتر به صف نمایه‌سازی جستجوی ابری (Cloud Search Indexing Queue) منتقل می‌شوند.

بازیابی و مدیریت هر مورد

برای مدیریت هر آیتم در صف نمایه‌سازی جستجوی ابری، تابع getDoc() را نادیده بگیرید. یک آیتم می‌تواند جدید، اصلاح‌شده، بدون تغییر یا دیگر در مخزن منبع وجود نداشته باشد. هر آیتم جدید یا اصلاح‌شده را بازیابی و نمایه‌گذاری کنید. آیتم‌هایی را که دیگر در مخزن منبع وجود ندارند، از نمایه حذف کنید.

متد getDoc() یک آیتم را از صف نمایه‌سازی جستجوی ابری گوگل می‌پذیرد. برای هر آیتم در صف، این مراحل را در متد getDoc() انجام دهید:

  1. بررسی کنید که آیا شناسه‌ی آیتم، در صف نمایه‌سازی جستجوی ابری، در مخزن وجود دارد یا خیر. در غیر این صورت، آیتم را از فهرست حذف کنید.

  2. وضعیت آیتم را از ایندکس نظرسنجی کنید و اگر آیتمی بدون تغییر ( ACCEPTED ) بود، هیچ کاری انجام ندهید.

  3. تغییر فهرست یا موارد جدید:

    1. مجوزها را تنظیم کنید.
    2. متادیتا (فراداده) را برای موردی که در حال فهرست‌بندی آن هستید، تنظیم کنید.
    3. متادیتا و آیتم را در یک RepositoryDoc قابل فهرست‌بندی ترکیب کنید.
    4. RepositoryDoc را برگردانید.

نکته: الگوی ListingConnector از برگرداندن null در متد getDoc() پشتیبانی نمی‌کند. برگرداندن null منجر به خطای NullPointerException.

رسیدگی به موارد حذف شده

قطعه کد زیر نشان می‌دهد که چگونه می‌توان تشخیص داد که آیا یک آیتم در مخزن وجود دارد یا خیر و در صورت عدم وجود، آن را حذف کرد.

نمونه پیمایش لیست.جاوا
String resourceName = item.getName();
int documentId = Integer.parseInt(resourceName);

if (!documents.containsKey(documentId)) {
  // Document no longer exists -- delete it
  log.info(() -> String.format("Deleting document %s", item.getName()));
  return ApiOperations.deleteItem(resourceName);
}

توجه داشته باشید که documents یک ساختار داده است که مخزن را نشان می‌دهد. اگر documentID در documents یافت نشد، APIOperations.deleteItem(resourceName) را برای حذف آیتم از فهرست، برگردانید.

رسیدگی به موارد بدون تغییر

قطعه کد زیر نحوه‌ی نظرسنجی از وضعیت آیتم در صف نمایه‌سازی جستجوی ابری و مدیریت آیتم بدون تغییر را نشان می‌دهد.

نمونه پیمایش لیست.جاوا
String currentHash = this.calculateMetadataHash(documentId);
if (this.canSkipIndexing(item, currentHash)) {
  // Document neither modified nor deleted, ack the push
  log.info(() -> String.format("Document %s not modified", item.getName()));
  PushItem pushItem = new PushItem().setType("NOT_MODIFIED");
  return new PushItems.Builder().addPushItem(resourceName, pushItem).build();
}

برای تعیین اینکه آیا مورد اصلاح نشده است، وضعیت مورد و همچنین سایر فراداده‌هایی که ممکن است نشان‌دهنده تغییر باشند را بررسی کنید. در مثال، از هش فراداده برای تعیین اینکه آیا مورد تغییر کرده است یا خیر استفاده می‌شود.

نمونه پیمایش لیست.جاوا
/**
 * Checks to see if an item is already up to date
 *
 * @param previousItem Polled item
 * @param currentHash  Metadata hash of the current github object
 * @return PushItem operation
 */
private boolean canSkipIndexing(Item previousItem, String currentHash) {
  if (previousItem.getStatus() == null || previousItem.getMetadata() == null) {
    return false;
  }
  String status = previousItem.getStatus().getCode();
  String previousHash = previousItem.getMetadata().getHash();
  return "ACCEPTED".equals(status)
      && previousHash != null
      && previousHash.equals(currentHash);
}

تنظیم مجوزها برای یک مورد

مخزن شما از یک فهرست کنترل دسترسی (ACL) برای شناسایی کاربران یا گروه‌هایی که به یک مورد دسترسی دارند استفاده می‌کند. ACL فهرستی از شناسه‌ها برای گروه‌ها یا کاربرانی است که می‌توانند به آن مورد دسترسی داشته باشند.

شما باید ACL مورد استفاده توسط مخزن خود را کپی کنید تا مطمئن شوید فقط کاربرانی که به یک مورد دسترسی دارند می‌توانند آن مورد را در نتیجه جستجو مشاهده کنند. ACL مربوط به یک مورد باید هنگام فهرست‌بندی یک مورد لحاظ شود تا جستجوی ابری گوگل اطلاعات لازم برای ارائه سطح صحیح دسترسی به آن مورد را داشته باشد.

کیت توسعه نرم‌افزار رابط محتوا (Content Connector SDK) مجموعه‌ای غنی از کلاس‌ها و روش‌های ACL را برای مدل‌سازی ACLهای اکثر مخازن ارائه می‌دهد. شما باید ACL هر آیتم موجود در مخزن خود را تجزیه و تحلیل کنید و هنگام فهرست‌بندی یک آیتم، یک ACL متناظر برای جستجوی ابری گوگل (Google Cloud Search) ایجاد کنید. اگر ACL مخزن شما از مفاهیمی مانند وراثت ACL استفاده می‌کند، مدل‌سازی آن ACL می‌تواند دشوار باشد. برای اطلاعات بیشتر در مورد ACLهای جستجوی ابری گوگل، به ACLهای جستجوی ابری گوگل (Google Cloud Search ACLs) مراجعه کنید.

نکته: API نمایه‌سازی جستجوی ابری از ACLهای تک دامنه‌ای پشتیبانی می‌کند. از ACLهای بین دامنه‌ای پشتیبانی نمی‌کند. از کلاس Acl.Builder برای تنظیم دسترسی به هر آیتم با استفاده از ACL استفاده کنید. قطعه کد زیر که از نمونه کامل پیمایش گرفته شده است، به همه کاربران یا «مدیران» ( getCustomerPrincipal() ) اجازه می‌دهد هنگام انجام جستجو، «خواننده» همه آیتم‌ها ( .setReaders() ) باشند.

نمونه پیمایش کامل.java
// Make the document publicly readable within the domain
Acl acl = new Acl.Builder()
    .setReaders(Collections.singletonList(Acl.getCustomerPrincipal()))
    .build();

برای مدل‌سازی صحیح ACLها برای مخزن، باید ACLها را درک کنید. به عنوان مثال، ممکن است در حال فهرست‌بندی فایل‌ها در یک سیستم فایل باشید که از نوعی مدل وراثت استفاده می‌کند که در آن پوشه‌های فرزند، مجوزها را از پوشه‌های والد به ارث می‌برند. مدل‌سازی وراثت ACL نیاز به اطلاعات اضافی دارد که در ACLهای جستجوی ابری گوگل پوشش داده شده است.

تنظیم فراداده برای یک آیتم

متادیتا در یک شیء Item ذخیره می‌شود. برای ایجاد یک Item ، حداقل به یک رشته منحصر به فرد به نام ID، نوع Item، ACL، URL و نسخه برای Item نیاز دارید. قطعه کد زیر نحوه ساخت یک Item با استفاده از کلاس کمکی IndexingItemBuilder را نشان می‌دهد.

نمونه پیمایش لیست.جاوا
// Url is required. Use google.com as a placeholder for this sample.
String viewUrl = "https://www.google.com";

// Version is required, set to current timestamp.
byte[] version = Longs.toByteArray(System.currentTimeMillis());

// Set metadata hash so queue can detect changes
String metadataHash = this.calculateMetadataHash(documentId);

// Using the SDK item builder class to create the document with
// appropriate attributes. This can be expanded to include metadata
// fields etc.
Item item = IndexingItemBuilder.fromConfiguration(Integer.toString(documentId))
    .setItemType(IndexingItemBuilder.ItemType.CONTENT_ITEM)
    .setAcl(acl)
    .setSourceRepositoryUrl(IndexingItemBuilder.FieldOrValue.withValue(viewUrl))
    .setVersion(version)
    .setHash(metadataHash)
    .build();

ایجاد یک آیتم قابل فهرست‌بندی

پس از تنظیم فراداده برای آیتم، می‌توانید آیتم قابل فهرست‌بندی واقعی را با استفاده از RepositoryDoc.Builder ایجاد کنید. مثال زیر نحوه ایجاد یک آیتم قابل فهرست‌بندی واحد را نشان می‌دهد.

نمونه پیمایش لیست.جاوا
// For this sample, content is just plain text
String content = String.format("Hello world from sample doc %d", documentId);
ByteArrayContent byteContent = ByteArrayContent.fromString("text/plain", content);

// Create the fully formed document
RepositoryDoc doc = new RepositoryDoc.Builder()
    .setItem(item)
    .setContent(byteContent, IndexingService.ContentFormat.TEXT)
    .build();

یک RepositoryDoc نوعی از ApiOperation است که درخواست واقعی IndexingService.indexItem() را انجام می‌دهد.

همچنین می‌توانید از متد setRequestMode() از کلاس RepositoryDoc.Builder برای شناسایی درخواست ایندکس‌گذاری به عنوان ASYNCHRONOUS یا SYNCHRONOUS استفاده کنید:

ASYNCHRONOUS
حالت ناهمزمان منجر به تأخیر طولانی‌تر از زمان ایندکس‌گذاری تا ارائه سرویس می‌شود و سهمیه توان عملیاتی زیادی را برای درخواست‌های ایندکس‌گذاری در نظر می‌گیرد. حالت ناهمزمان برای ایندکس‌گذاری اولیه (backfill) کل مخزن توصیه می‌شود.
SYNCHRONOUS
حالت همگام منجر به کاهش تأخیر در نمایه‌سازی تا ارائه سرویس می‌شود و سهمیه توان عملیاتی محدودی را در خود جای می‌دهد. حالت همگام برای نمایه‌سازی به‌روزرسانی‌ها و تغییرات در مخزن توصیه می‌شود. در صورت عدم تعیین، حالت درخواست به طور پیش‌فرض روی SYNCHRONOUS تنظیم می‌شود.

مراحل بعدی

در اینجا چند گام بعدی که می‌توانید بردارید، آورده شده است:

ایجاد یک رابط پیمایش گراف با استفاده از یک کلاس الگو

صف نمایه‌سازی جستجوی ابری برای نگهداری شناسه‌ها و مقادیر هش اختیاری برای هر مورد در مخزن استفاده می‌شود. یک رابط پیمایش گراف، شناسه‌های مورد را به صف نمایه‌سازی جستجوی ابری گوگل (Google Cloud Search Indexing Queue) ارسال می‌کند و آنها را یکی یکی برای نمایه‌سازی بازیابی می‌کند. جستجوی ابری گوگل صف‌ها را نگهداری می‌کند و محتوای صف را برای تعیین وضعیت مورد، مانند اینکه آیا یک مورد از مخزن حذف شده است یا خیر، مقایسه می‌کند. برای اطلاعات بیشتر در مورد صف نمایه‌سازی جستجوی ابری، به صف نمایه‌سازی جستجوی ابری گوگل (Google Cloud Search Indexing Queue) مراجعه کنید.

در طول ایندکس، محتوای آیتم از مخزن داده‌ها واکشی می‌شود و شناسه‌های آیتم‌های فرزند به صف اضافه می‌شوند. رابط به صورت بازگشتی پردازش شناسه‌های والد و فرزند را تا زمانی که همه آیتم‌ها مدیریت شوند، ادامه می‌دهد.

این بخش از مستندات به قطعه کدهایی از مثال GraphTraversalSample اشاره دارد.

نقطه ورود کانکتور را پیاده‌سازی کنید

نقطه ورود به یک کانکتور، متد main() است. وظیفه اصلی این متد ایجاد یک نمونه از کلاس Application و فراخوانی متد start() آن برای اجرای کانکتور است.

قبل از فراخوانی application.start() ، از کلاس IndexingApplication.Builder برای نمونه‌سازی الگوی ListingConnector استفاده کنید. ListingConnector یک شیء Repository را می‌پذیرد که متدهای آن را پیاده‌سازی می‌کنید.

قطعه کد زیر نحوه نمونه‌سازی ListingConnector و Repository مرتبط با آن را نشان می‌دهد:

GraphTraversalSample.java
/**
 * This sample connector uses the Cloud Search SDK template class for a graph
 * traversal connector.
 *
 * @param args program command line arguments
 * @throws InterruptedException thrown if an abort is issued during initialization
 */
public static void main(String[] args) throws InterruptedException {
  Repository repository = new SampleRepository();
  IndexingConnector connector = new ListingConnector(repository);
  IndexingApplication application = new IndexingApplication.Builder(connector, args).build();
  application.start();
}

در پشت صحنه، SDK متد initConfig() را پس از فراخوانی Application.build توسط متد main() کانکتور شما، فراخوانی می‌کند. متد initConfig() به صورت زیر است:

  1. متد Configuation.isInitialized() را فراخوانی می‌کند تا مطمئن شود که Configuration مقداردهی اولیه نشده است.
  2. یک شیء Configuration را با جفت‌های کلید-مقدار ارائه شده توسط گوگل مقداردهی اولیه می‌کند. هر جفت کلید-مقدار در یک شیء ConfigValue درون شیء Configuration ذخیره می‌شود.

پیاده‌سازی رابط Repository )

تنها هدف شیء Repository انجام پیمایش و فهرست‌بندی اقلام مخزن است. هنگام استفاده از یک الگو، برای ایجاد یک رابط محتوا، فقط باید متدهای خاصی را در رابط Repository بازنویسی کنید. متدهایی که شما بازنویسی می‌کنید به الگو و استراتژی پیمایشی که استفاده می‌کنید بستگی دارد. برای ListingConnector ، متدهای زیر را بازنویسی می‌کنید:

  • متد init() . برای انجام هرگونه تنظیم و مقداردهی اولیه مخزن داده، متد init() را بازنویسی کنید.

  • متد getIds() . برای بازیابی شناسه‌ها و مقادیر هش برای همه رکوردهای موجود در مخزن، متد getIds() را بازنویسی کنید.

  • متد getDoc() . برای افزودن، به‌روزرسانی، تغییر یا حذف آیتم‌ها از اندیس، متد getDoc() را بازنویسی کنید.

  • (اختیاری) متد getChanges() . اگر مخزن شما از تشخیص تغییر پشتیبانی می‌کند، متد getChanges() را بازنویسی کنید. این متد برای هر پیمایش افزایشی برنامه‌ریزی‌شده (مطابق با پیکربندی شما) یک بار فراخوانی می‌شود تا موارد تغییر یافته را بازیابی و فهرست‌بندی کند.

  • (اختیاری) متد close() . اگر نیاز به پاکسازی مخزن دارید، متد close() را بازنویسی کنید. این متد یک بار در هنگام خاموش شدن کانکتور فراخوانی می‌شود.

هر یک از متدهای شیء Repository نوعی از شیء ApiOperation را برمی‌گرداند. یک شیء ApiOperation عملی را به شکل یک یا شاید چندین فراخوانی IndexingService.indexItem() برای انجام فهرست‌بندی واقعی مخزن شما انجام می‌دهد.

دریافت پارامترهای پیکربندی سفارشی

به عنوان بخشی از مدیریت پیکربندی کانکتور، شما نیاز به دریافت پارامترهای سفارشی از شیء Configuration خواهید داشت. این کار معمولاً در متد init() کلاس Repository انجام می‌شود.

کلاس Configuration متدهای مختلفی برای دریافت انواع داده‌های مختلف از یک پیکربندی دارد. هر متد یک شیء ConfigValue را برمی‌گرداند. سپس از متد get() شیء ConfigValue برای بازیابی مقدار واقعی استفاده خواهید کرد. قطعه کد زیر، از FullTraversalSample ، نحوه بازیابی یک مقدار صحیح سفارشی از یک شیء Configuration را نشان می‌دهد:

نمونه پیمایش کامل.java
@Override
public void init(RepositoryContext context) {
  log.info("Initializing repository");
  numberOfDocuments = Configuration.getInteger("sample.documentCount", 10).get();
}

برای دریافت و تجزیه یک پارامتر حاوی چندین مقدار، از یکی از تجزیه‌کننده‌های نوع کلاس Configuration برای تجزیه داده‌ها به تکه‌های گسسته استفاده کنید. قطعه کد زیر، از رابط آموزشی، از متد getMultiValue برای دریافت لیستی از نام‌های مخزن GitHub استفاده می‌کند:

مخزن گیت‌هاب.جاوا
ConfigValue<List<String>> repos = Configuration.getMultiValue(
    "github.repos",
    Collections.emptyList(),
    Configuration.STRING_PARSER);

پیمایش گراف را انجام دهید

متد getIds() را برای بازیابی شناسه‌ها و مقادیر هش برای همه رکوردهای موجود در مخزن، بازنویسی کنید. متد getIds() یک نقطه بررسی (checkpoint) می‌پذیرد. این نقطه بررسی برای از سرگیری فهرست‌بندی در یک مورد خاص در صورت قطع شدن فرآیند استفاده می‌شود.

در مرحله بعد، متد getDoc() را برای مدیریت هر آیتم در صف نمایه‌سازی جستجوی ابری، بازنویسی کنید.

شناسه‌های آیتم و مقادیر هش را فشار دهید

تابع getIds() را برای دریافت شناسه‌های آیتم‌ها و مقادیر هش محتوای مرتبط با آنها از مخزن، بازنویسی کنید. سپس جفت‌های شناسه و مقدار هش در درخواست عملیات ارسال به صف نمایه‌سازی جستجوی ابری بسته‌بندی می‌شوند. شناسه‌های ریشه یا والد معمولاً ابتدا و به دنبال آن شناسه‌های فرزند تا زمانی که کل سلسله مراتب آیتم‌ها پردازش شود، ارسال می‌شوند.

The getIds() method accepts a checkpoint representing the last item to be indexed. The checkpoint can be used to resume indexing at a specific item should the process be interrupted. For each item in your repository, perform these steps in the getIds() method:

  • Get each item ID and associated hash value from the repository.
  • Package each ID and hash value pair into a PushItems .
  • Combine each PushItems into an iterator returned by the getIds() method. Note that getIds() actually returns a CheckpointCloseableIterable which is an iteration of ApiOperation objects, each object representing an API request performed on a RepositoryDoc , such as push the items to the queue.

The following code snippet shows how to get each item ID and hash value and insert them into a PushItems . A PushItems is an ApiOperation request to push an item to the Cloud Search Indexing Queue.

GraphTraversalSample.java
PushItems.Builder allIds = new PushItems.Builder();
PushItem item = new PushItem();
allIds.addPushItem("root", item);

The following code snippet shows how to use the PushItems.Builder class to package the IDs and hash values into a single push ApiOperation .

GraphTraversalSample.java
ApiOperation pushOperation = allIds.build();
CheckpointCloseableIterable<ApiOperation> iterator =
  new CheckpointCloseableIterableImpl.Builder<>(
      Collections.singletonList(pushOperation))
  .build();

Items are pushed to the Cloud Search Indexing Queue for further processing.

Retrieve and handle each item

Override getDoc() to handle each item in the Cloud Search Indexing Queue. An item can be new, modified, unchanged, or can no longer exist in the source repository. Retrieve and index each item that is new or modified. Remove items from the index that no longer exist in the source repository.

The getDoc() method accepts an Item from the Cloud Search Indexing Queue. For each item in the queue, perform these steps in the getDoc() method:

  1. Check if the item's ID, within the Cloud Search Indexing Queue, exists in the repository. If not, delete the item from the index. If the item does exist, continue with the next step.

  2. Index changed or new items:

    1. Set the permissions.
    2. Set the metadata for the item that you are indexing.
    3. Combine the metadata and item into one indexable RepositoryDoc .
    4. Place the child IDs in the Cloud Search Indexing Queue for further processing.
    5. Return the RepositoryDoc .

Handle deleted items

The following code snippet shows how to determine if an item exists in the index and, it not, delete it.

GraphTraversalSample.java
String resourceName = item.getName();
if (documentExists(resourceName)) {
  return buildDocumentAndChildren(resourceName);
}
// Document doesn't exist, delete it
log.info(() -> String.format("Deleting document %s", resourceName));
return ApiOperations.deleteItem(resourceName);

Set the permissions for an item

Your repository uses an Access Control List (ACL) to identify the users or groups that have access to an item. An ACL is a list of IDs for groups or users who can access the item.

You must duplicate the ACL used by your repository to ensure only those users with access to an item can see that item within a search result. The ACL for an item must be included when indexing an item so that Google Cloud Search has the information it needs to provide the correct level of access to the item.

The Content Connector SDK provides a rich set of ACL classes and methods to model the ACLs of most repositories. You must analyze the ACL for each item in your repository and create a corresponding ACL for Google Cloud Search when you index an item. If your repository's ACL employs concepts such as ACL inheritance, modeling that ACL can be tricky. For further information on Google Cloud Search ACLs, refer to Google Cloud Search ACLs .

Note: The Cloud Search Indexing API supports single-domain ACLs. It does not support cross-domain ACLs. Use the Acl.Builder class to set access to each item using an ACL. The following code snippet, taken from the full traversal sample, allows all users or “principals” ( getCustomerPrincipal() ) to be “readers” of all items ( .setReaders() ) when performing a search.

FullTraversalSample.java
// Make the document publicly readable within the domain
Acl acl = new Acl.Builder()
    .setReaders(Collections.singletonList(Acl.getCustomerPrincipal()))
    .build();

You need to understand ACLs to properly model ACLs for the repository. For example, you might be indexing files within a file system that uses some sort of inheritance model whereby child folders inherit permissions from parent folders. Modeling ACL inheritance requires additional information covered in Google Cloud Search ACLs

Set the metadata for an item

Metadata is stored in an Item object. To create an Item , you need a minimum of a unique string ID, item type, ACL, URL, and version for the item. The following code snippet shows how to build an Item using the IndexingItemBuilder helper class.

GraphTraversalSample.java
// Url is required. Use google.com as a placeholder for this sample.
String viewUrl = "https://www.google.com";

// Version is required, set to current timestamp.
byte[] version = Longs.toByteArray(System.currentTimeMillis());

// Using the SDK item builder class to create the document with
// appropriate attributes. This can be expanded to include metadata
// fields etc.
Item item = IndexingItemBuilder.fromConfiguration(documentId)
    .setItemType(IndexingItemBuilder.ItemType.CONTENT_ITEM)
    .setAcl(acl)
    .setSourceRepositoryUrl(IndexingItemBuilder.FieldOrValue.withValue(viewUrl))
    .setVersion(version)
    .build();

Create the indexable item

Once you have set the metadata for the item, you can create the actual indexable item using the RepositoryDoc.Builder . The following example shows how to create a single indexable item.

GraphTraversalSample.java
// For this sample, content is just plain text
String content = String.format("Hello world from sample doc %s", documentId);
ByteArrayContent byteContent = ByteArrayContent.fromString("text/plain", content);

RepositoryDoc.Builder docBuilder = new RepositoryDoc.Builder()
    .setItem(item)
    .setContent(byteContent, IndexingService.ContentFormat.TEXT);

A RepositoryDoc is a type of ApiOperation that performs the actual IndexingService.indexItem() request.

You can also use the setRequestMode() method of the RepositoryDoc.Builder class to identify the indexing request as ASYNCHRONOUS or SYNCHRONOUS :

ASYNCHRONOUS
Asynchronous mode results in longer indexing-to-serving latency and accommodates large throughput quota for indexing requests. Asynchronous mode is recommended for initial indexing (backfill) of the entire repository.
SYNCHRONOUS
Synchronous mode results in shorter indexing-to-serving latency and accommodates limited throughput quota. Synchronous mode is recommended for indexing of updates and changes to the repository. If unspecified, the request mode defaults to SYNCHRONOUS .

Place the child IDs in the Cloud Search Indexing Queue

The following code snippet shows how to include the child IDs, for the currently processing parent item, into the queue for processing. These IDs are processed after the parent item is indexed.

GraphTraversalSample.java
// Queue the child nodes to visit after indexing this document
Set<String> childIds = getChildItemNames(documentId);
for (String id : childIds) {
  log.info(() -> String.format("Pushing child node %s", id));
  PushItem pushItem = new PushItem();
  docBuilder.addChildId(id, pushItem);
}

RepositoryDoc doc = docBuilder.build();

مراحل بعدی

Here are a few next steps you might take:

Create a content connector using the REST API

The following sections explain how to create a content connector using the REST API.

Determine your traversal strategy

The primary function of a content connector is to traverse a repository and index its data. You must implement a traversal strategy based on the size and layout of data in your repository. Following are three common traversal strategies:

Full traversal strategy

A full traversal strategy scans the entire repository and blindly indexes every item. This strategy is commonly used when you have a small repository and can afford the overhead of doing a full traversal every time you index.

This traversal strategy is suitable for small repositories with mostly static, non-hierarchical, data. You might also use this traversal strategy when change detection is difficult or not supported by the repository.

List traversal strategy

A list traversal strategy scans the entire repository, including all child nodes, determining the status of each item. Then, the connector takes a second pass and only indexes items that are new or have been updated since the last indexing. This strategy is commonly used to perform incremental updates to an existing index (instead of having to do a full traversal every time you update the index).

This traversal strategy is suitable when change detection is difficult or not supported by the repository, you have non-hierarchical data, and you are working with very large data sets.

پیمایش گراف

A graph traversal strategy scans the entire parent node determining the status of each item. Then, the connector takes a second pass and only indexes items in the root node are new or have been updated since the last indexing. Finally, the connector passes any child IDs then indexes items in the child nodes that are new or have been updated. The connector continues recursively through all child nodes until all items have been addressed. Such traversal is typically used for hierarchical repositories where listing of all IDs isn't practical.

This strategy is suitable if you have hierarchical data that needs to be crawled, such as a series directories or web pages.

Implement your traversal strategy and index items

Every indexable element for Cloud Search is referred to as an item in the Cloud Search API. An item might be a file, folder, a line in a CSV file, or a database record.

Once your schema is registered, you can populate the index by:

  1. (optional) Using items.upload to upload files larger than 100KiB for indexing. For smaller files, embed the content as inlineContent using items.index .

  2. (optional) Using media.upload to upload media files for indexing.

  3. Using items.index to index the item. For example, if your schema uses the object definition in the movie schema , an indexing request for a single item would look like this:

    {
      "name": "datasource/<data_source_id>/items/titanic",
      "acl": {
        "readers": [
          {
            "gsuitePrincipal": {
              "gsuiteDomain": true
            }
          }
        ]
      },
      "metadata": {
        "title": "Titanic",
        "viewUrl": "http://www.imdb.com/title/tt2234155/?ref_=nv_sr_1",
        "objectType": "movie"
      },
      "structuredData": {
        "object": {
          "properties": [
            {
              "name": "movieTitle",
              "textValues": {
                "values": [
                  "Titanic"
                ]
              }
            },
            {
              "name": "releaseDate",
              "dateValues": {
                "values": [
                  {
                    "year": 1997,
                    "month": 12,
                    "day": 19
                  }
                ]
              }
            },
            {
              "name": "actorName",
              "textValues": {
                "values": [
                  "Leonardo DiCaprio",
                  "Kate Winslet",
                  "Billy Zane"
                ]
              }
            },
            {
              "name": "genre",
              "enumValues": {
                "values": [
                  "Drama",
                  "Action"
                ]
              }
            },
            {
              "name": "userRating",
              "integerValues": {
                "values": [
                  8
                ]
              }
            },
            {
              "name": "mpaaRating",
              "textValues": {
                "values": [
                  "PG-13"
                ]
              }
            },
            {
              "name": "duration",
              "textValues": {
                "values": [
                  "3 h 14 min"
                ]
              }
            }
          ]
        }
      },
      "content": {
        "inlineContent": "A seventeen-year-old aristocrat falls in love with a kind but poor artist aboard the luxurious, ill-fated R.M.S. Titanic.",
        "contentFormat": "TEXT"
      },
      "version": "01",
      "itemType": "CONTENT_ITEM"
    }
    
  4. (Optional) Using items.get calls to verify an item has been indexed.

To perform a full traversal, you would periodically reindex the entire repository. To perform a list or graph traversal, you need to implement code to handle repository changes .

Handle repository changes

You can periodically gather and index each item from a repository to perform a full indexing. While effective at ensuring your index is up-to-date, a full indexing can be costly when dealing with larger or hierarchical repositories.

Instead of using index calls to index an entire repository every so often, you can also use the Google Cloud Indexing Queue as a mechanism for tracking changes and only indexing those items that have changed. You can use the items.push requests to push items into the queue for later polling and updating. For more information on the Google Cloud Indexing Queue, refer to Google Cloud Indexing Queue .

For further information on the Google Cloud Search API, refer to Cloud Search API .