2 - 创建和加载包含 JavaScript 的搜索索引

按照以下步骤继续生成启用搜索的网站:

创建 Azure 认知搜索资源

使用 PowerShell 和 Az.Search 模块创建新的搜索资源。 在本部分中,你还将创建用于对索引进行读取访问的查询密钥,并获取用于添加对象的内置管理密钥。

  1. 在 Visual Studio Code 中打开一个新的终端窗口。

  2. 连接到 Azure:

    Connect-AzAccount -Environment AzureChinaCloud -TenantID <your-tenant-ID>
    

    注意

    可能需要提供租户 ID,可在 Azure 门户中的“门户设置”>“目录 + 订阅”中找到此 ID。

  3. 在创建新的搜索服务之前,可以列出订阅的现有搜索服务以查看其中是否有自己需要使用的服务:

    Get-AzResource -ResourceType Microsoft.Search/searchServices | ft
    
  4. 加载 Az.Search 模块:

    Install-Module -Name Az.Search -Scope CurrentUser
    
  5. 创建新搜索服务。 将 cmdlet 作为模板,将资源组、服务名称、层、区域、分区和副本替换为有效值:

    New-AzSearchService -ResourceGroupName "my resource group"  -Name "myDemoSearchSvc" -Sku "Free" -Location "China North" -PartitionCount 1 -ReplicaCount 1 -HostingMode Default
    
    Prompt Enter
    为新搜索服务输入全局唯一名称。 请记住此名称。 此资源名称将成为您的资源终结点的一部分。
    选择新资源的资源组 使用为本教程创建的资源组。
    选择搜索服务的 SKU。 在此本教程中,请选择免费 SKU。 创建服务后无法更改 SKU 定价层。
    选择新资源的位置。 选择附近的区域。
  6. 创建向搜索服务授予读取访问权限的查询密钥。 必须显式创建查询密钥。 将查询密钥复制到记事本,以便在后面的步骤中将其粘贴到客户端代码中:

    New-AzSearchQueryKey -ResourceGroupName "my resource group"  -ServiceName "myDemoSearchSvc" -Name "mySrchQueryKey"
    
  7. 获取为搜索服务自动创建的搜索服务管理 API 密钥。 管理 API 密钥提供对搜索服务的写入访问权限。 将任一管理密钥复制到记事本,以便在创建和加载索引的批量导入步骤中使用它:

    Get-AzSearchAdminKeyPair  -ResourceGroupName "my resource group" -ServiceName "myDemoSearchSvc" 
    

此脚本使用 Azure SDK 进行认知搜索:

  1. 在 Visual Studio Code 中,在子目录 search-website-functions-v4/bulk-insert 中打开 bulk_insert_books.js 文件,将以下变量替换为您自己的值,以便使用 Azure 搜索 SDK 进行身份验证:

    • YOUR-SEARCH-RESOURCE-NAME
    • YOUR-SEARCH-ADMIN-KEY
/**
 * Add documents into Search Index
 * Script creates a new index called `good-books` in your Search resource.
 * 
 * 1. Edit the values for your own Search resource.
 *     * YOUR-SEARCH-RESOURCE-NAME
 *     * YOUR-SEARCH-ADMIN-KEY
 * 2. Run script with `npm install && npm start`
 *  
 */

const axios = require('axios');
const Papa = require('papaparse')
const { SearchClient, SearchIndexClient, AzureKeyCredential } = require("@azure/search-documents");

const SEARCH_ENDPOINT = "https://YOUR-SEARCH-RESOURCE-NAME.search.azure.cn";
const SEARCH_KEY = "YOUR-SEARCH-ADMIN-KEY";

const SEARCH_INDEX_NAME = "good-books";
const SEARCH_INDEX_SCHEMA = require("./good-books-index.json");

const BOOKS_URL = "https://raw.githubusercontent.com/zygmuntz/goodbooks-10k/master/books.csv";
const BATCH_SIZE = 1000;

// Create Search service client
// used to upload docs into Index
const client = new SearchClient(
    SEARCH_ENDPOINT,
    SEARCH_INDEX_NAME,
    new AzureKeyCredential(SEARCH_KEY)
);

// Create Search service Index client
// used to create new Index
const clientIndex = new SearchIndexClient(
    SEARCH_ENDPOINT,
    new AzureKeyCredential(SEARCH_KEY)
);

// Insert docs into Search Index
// in batch
const insertData = async (data) => {

    let batch = 0;
    let batchArray = [];
    
    for (let i = 0; i < data.length; i++) {
        
        const row = data[i];
       
        // Convert string data to typed data
        // Types are defined in schema
        batchArray.push({
            "id": row.book_id,
            "goodreads_book_id": parseInt(row.goodreads_book_id),
            "best_book_id": parseInt(row.best_book_id),
            "work_id": parseInt(row.work_id),
            "books_count": !row.books_count ? 0 : parseInt(row.books_count),
            "isbn": row.isbn,
            "isbn13": row.isbn13,
            "authors": row.authors.split(",").map(name => name.trim()),
            "original_publication_year": !row.original_publication_year ? 0 : parseInt(row.original_publication_year),
            "original_title": row.original_title,
            "title": row.title,
            "language_code": row.language_code,
            "average_rating": !row.average_rating ? 0 : parseFloat(row.average_rating),
            "ratings_count": !row.ratings_count ? 0 : parseInt(row.ratings_count),
            "work_ratings_count": !row.work_ratings_count ? 0 : parseInt(row.work_ratings_count),
            "work_text_reviews_count": !row.work_text_reviews_count ? 0 : parseInt(row.work_text_reviews_count),
            "ratings_1": !row.ratings_1 ? 0 : parseInt(row.ratings_1),
            "ratings_2": !row.ratings_2 ? 0 : parseInt(row.ratings_2),
            "ratings_3": !row.ratings_3 ? 0 : parseInt(row.ratings_3),
            "ratings_4": !row.ratings_4 ? 0 : parseInt(row.ratings_4),
            "ratings_5": !row.ratings_5 ? 0 : parseInt(row.ratings_5),
            "image_url": row.image_url,
            "small_image_url": row.small_image_url
        })
        
        console.log(`${i}`);
        
        // Insert batch into Index
        if ((batchArray.length % BATCH_SIZE) === 0){
            await client.uploadDocuments(batchArray);
            
            console.log(`BATCH SENT`);
            batchArray = [];
        }
        
    }
    // Insert any final batch into Index
    if (batchArray.length > 0 ){
        await client.uploadDocuments(batchArray);
        
        console.log(`FINAL BATCH SENT`);
        batchArray = [];
    }
}
const bulkInsert = async () => {

    // Download CSV Data file
    const response = await axios.get(BOOKS_URL);
    const fileData = response.data;

    // convert CSV to JSON
    const dataObj = Papa.parse(fileData, {
        header: true,
        encoding: 'utf8',
        skipEmptyLines: true,
    })
    
    // Insert JSON into Search Index
    await insertData(dataObj.data)
}

// Create Search Index
async function createIndex() {

    SEARCH_INDEX_SCHEMA.name = SEARCH_INDEX_NAME;
    const result = await clientIndex.createIndex(SEARCH_INDEX_SCHEMA);

    console.log(result);
}

const main = async () => {

    await createIndex();
    console.log("index created");

    await bulkInsert();
}

main()
.then(() => console.log('done'))
.catch((err) => {
    console.log(`done +  failed ${err}`)
});
  1. 在 Visual Studio 中打开用于项目目录的子目录 search-website-functions-v4/bulk-insert 的集成终端,并运行以下命令以安装依赖项。

    npm install 
    
  1. 继续使用 Visual Studio 中的集成终端作为项目目录的子目录 search-website-functions-v4/bulk-insert,以运行 bulk_insert_books.js 脚本:

    npm start
    
  2. 当代码运行时,控制台将显示进度。

  3. 上传完成后,打印到控制台的最后一个语句将为“已完成”。

查看新的搜索索引

上传完成后,便可以使用搜索索引。 在 Azure 门户中查看新索引。

  1. 在 Azure 门户中,找到在上一步中创建的搜索服务

  2. 在左侧,选择“索引”,然后选择好书索引。

    Expandable screenshot of Azure portal showing the index.

  3. 默认情况下,索引将在“搜索资源管理器”选项卡中打开。选择“搜索”以从索引返回文档。

    Expandable screenshot of Azure portal showing search results

回滚批量导入文件更改

bulk-insert 目录中的 Visual Studio Code 集成终端使用以下 git 命令来回滚更改。 它们不是继续学习教程所必需的,不应将这些机密保存或推送到你的存储库。

git checkout .

复制搜索资源名称

记下搜索资源名称。 将 Azure Function 应用连接到搜索资源时需要用到它。

注意

尽管你可能想要在 Azure 函数中使用搜索管理密钥,但这并不符合最低特权原则。 Azure Function 将使用查询密钥以符合最小特权。

后续步骤

部署静态 Web 应用