const Typesense = require('typesense'); const fs = require('fs'); const xml2js = require('xml2js'); // --- 配置区域 --- const CONFIG = { apiKey: 'tDPfzkghH3Zy55DHyWOnYkQiijOqN8bx', // 必须是 Admin Key host: 'typesense.biss.click', port: 443, protocol: 'https', collectionName: 'blogs' }; const client = new Typesense.Client({ 'nodes': [{ 'host': CONFIG.host, 'port': CONFIG.port, 'protocol': CONFIG.protocol }], 'apiKey': CONFIG.apiKey, 'connectionTimeoutSeconds': 5 }); async function sync() { try { // 1. 读取并解析 XML const xml = fs.readFileSync('./public/search.xml', 'utf8'); const parser = new xml2js.Parser({ explicitArray: false }); const result = await parser.parseStringPromise(xml); // 提取文章列表 (处理单篇文章和多篇文章的情况) let entries = result.search.entry; if (!Array.isArray(entries)) entries = [entries]; // 格式化数据以适配 Typesense const documents = entries.map(post => ({ title: post.title, url: post.url, content: post.content, categories: post.categories ? (Array.isArray(post.categories.category) ? post.categories.category : [post.categories.category]) : [], tags: post.tags ? (Array.isArray(post.tags.tag) ? post.tags.tag : [post.tags.tag]) : [], })); // 2. 检查或创建 Collection (Schema) try { await client.collections(CONFIG.collectionName).retrieve(); } catch (err) { const schema = { name: CONFIG.collectionName, fields: [ // 关键点:指定 locale 为 'zh' 开启中文分词 { name: 'title', type: 'string', locale: 'zh' }, { name: 'content', type: 'string', locale: 'zh' }, { name: 'url', type: 'string' }, { name: 'categories', type: 'string[]', facet: true }, { name: 'tags', type: 'string[]', facet: true } ] }; await client.collections().create(schema); console.log('Collection created with Chinese support!'); } // 3. 导入数据 (使用 upsert 模式:存在则更新,不存在则创建) console.log(`Syncing ${documents.length} posts to Typesense...`); await client.collections(CONFIG.collectionName).documents().import(documents, { action: 'upsert' }); console.log('Sync complete!'); } catch (error) { console.error('Sync failed:', error); } } sync();