跳到主要内容

知识加工

知识加工是指根据实际业务数据生成知识库的能力,主要包含以下两个方面:

  • 通过配置schema生成知识加工的产物(如倒排表、向量库、向量表),这些产物最终用于知识问答过程中的检索。schema的配置应基于实际业务使用的数据库及数据表结构。知识加工和检索对中文处理进行了优化,因此中文问答的效果优于英文。
  • 通过调用获取知识加工状态的接口,查询当前的加工状态。

知识加工支持处理如下文件类型。

  • 文本和网页类型:txt、html。
  • 办公文件类型:doc、docx、ppt、pptx、xls、xlsx、pdf,仅支持纯文本的基本处理,复杂或特定内容可由应用侧自行解析处理后转成txt格式进行后续加工。
  • 图片类型:jpeg、jpg、png。

从6.1.0(23)版本开始,新增支持关键字表和时间特征表。当前知识加工生成的产物结构如下:

表1 倒排表结构

列名类型含义
reference_idUNINDEXED关联id,与业务表主键id对应。
chunk_idUNINDEXED用于标识每一个切分后的Chunk。一个Chunk代表需要进行知识加工的文本的一个切片。
chunk_sourceUNINDEXED每个Chunk在业务表中的字段归属。
chunk_textTEXT倒排索引字段,每个Chunk的文本内容。

表2 向量表结构

列名类型含义
idINTEGER自增主键。
reference_idINTEGER关联id,与业务表主键id对应。
chunk_idTEXT用于标识每一个切分后的Chunk。一个Chunk代表需要进行知识加工的文本的一个切片。
chunk_sourceTEXT每个Chunk在业务表中的字段归属。
reprFLOATVECTOR(128)chunk_id对应的文本的向量表征。
ScalarTEXTSchema中定义的所有标量字段,类型均为TEXT。

表3 关键字表结构

列名类型含义
idINTEGER自增主键。
reference_idINTEGER关联id,与业务表主键id对应。
chunk_idTEXT用于标识每一个切分后的Chunk。一个Chunk代表需要进行知识加工的文本的一个切片。
wordTEXT匹配到的关键字。
extendFieldsTEXTSchema中customKeyword字段下extendFields定义的所有列,每个字段一列,类型均为TEXT。

表4 时间特征表结构

列名类型含义
idINTEGER自增主键。
reference_idINTEGER关联id,与业务表主键id对应。
chunk_idTEXT用于标识每一个切分后的Chunk。一个Chunk代表需要进行知识加工的文本的一个切片。
start_timeTEXT匹配到的时间段的开始时间。
end_timeTEXT匹配到的时间段的结束时间。
extendFieldsTEXTSchema中time字段下extendFields定义的所有列,每个字段一列,类型均为TEXT。

触发知识加工的时机

触发知识加工包含下列两种情况。

  • 通过开发步骤配置knowledge_schema.json和开库参数后,每次开库都会启动一次知识加工任务。
  • 当已经成功开库并且存在一个活跃的数据库连接时,数据源表发生数据变更(插入、更新、删除)时会自动触发加工任务。

约束限制

  1. 知识加工使用的表不支持同时进行端端同步、端云同步以及搜索。
  2. 知识加工schema配置文件为src/main/resources/rawfile/arkdata/knowledge/knowledge_schema.json,文件内容必须是合法的Json字符串。
  3. 知识加工清理接口:在schema升级场景下,首次开库或调用getKnowledgeProcessor接口前调用cleanKnowledgeData接口。

接口说明

知识加工关键接口common.BaseContext如下表所示,具体API说明详见API参考

接口名描述
getKnowledgeProcessor(context: common.BaseContext, config: KnowledgeProcessorConfig): Promise<KnowledgeProcessor>获取知识加工对象,进行获取知识加工状态等操作。
getStatus(): Promise<ProcessorStatus>获取知识加工状态。
startProcess(option: KnowledgeProcessConfig): Promise<void>根据入参的配置,启动知识加工。
stopProcess(): Promise<void>停止当前知识加工。
cleanKnowledgeData(context: common.BaseContext, config: KnowledgeProcessorConfig): Promise<void>清理知识库,根据入参中的知识加工配置获取对应知识库信息,将知识库进行清理。
getRdbStore(context: Context, config: StoreConfig): Promise<RdbStore>创建或打开已有的关系型数据库,按照步骤2配置开库参数后,调用该接口可触发知识加工。

开发步骤

从6.1.0(23)版本开始,知识加工schema配置文件knowledge_schema.json新增支持commonAttribute和customKeyword参数;knowledgeField的type字段新增支持Markdown类型。

  1. 配置知识加工schema文件knowledge_schema.json,下文是配置示例,实际文件内容请根据业务需要进行配置。知识加工产物命名规则如下:

    • 倒排库与数据源库是同一个数据库。
    • 倒排表名相较于数据源表名增加了"_inverted"后缀(email->email_inverted)。
    • 向量库名相较于数据源库名增加了"_vector"后缀(testmail_store.db->testmail_store_vector.db)。
    • 向量表名相较于数据源表名增加了"_vector"后缀(email->email_vector)。
    // 文件路径:src/main/resources/rawfile/arkdata/knowledge/knowledge_schema.json
    // 项目中没有该目录请递归创建
    // 实际使用时请去除注释,示例中增加注释仅作字段说明用
    {
    "knowledgeSource": [{
    "version": 1,
    "dbName": "testmail_store.db", // 存储原始数据的数据库文件名
    "tables": [{
    "tableName": "email", // 用于知识加工的表名
    "referenceFields": ["id"], // 知识数据源引用字段,用于关联知识库中的数据
    "processSequence": { // 定义加工顺序为id倒序
    "columnName": "id",
    "sortType": "DESC"
    },
    "customKeyword": {
    "wordTablePath": "/data/storage/el2/base/haps/entry/files/keywords.txt", // 此处仅作示例,实际文件路径根据业务实际情况配置
    "sourceFields": ["subject", "content"], // 关键字提取生效的列
    "extendFields": [] // 创建关键字表时额外增加的列,数据与源表一致
    },
    "commonAttribute": {
    "time": {
    "baseTimeField": "received_date",
    "sourceFields": ["subject", "content"],
    "extendFields": ["sender"]
    }
    },
    "knowledgeFields": [{ // 关注的知识字段
    "columnName": "subject", // 关注的字段名称
    "type": ["Text"] // 关注的字段类型,Text则表示要做向量和倒排
    },
    {
    "columnName": "content",
    "type": ["Text"]
    },
    {
    "columnName": "image_text",
    "type": ["Text"]
    },
    {
    "columnName": "attachment_names",
    "type": ["Text"]
    },
    {
    "columnName": "inline_files",
    "type": ["Json"],
    "parser": [
    {
    "type": "File",
    "path": "$[*].uri" // path字段的值为Json路径表达式
    }
    ]
    },
    {
    "columnName": "sender",
    "type": ["Scalar"], // Scalar表示标量字段,不做加工,直接写到向量数据表中对应的列,用于标量检索过滤
    "description": "sender"
    },
    {
    "columnName": "receivers",
    "type": ["Scalar"],
    "description": "receivers"
    },
    {
    "columnName": "received_date",
    "type": ["Scalar"],
    "description": "received_date"
    }],
    "pipelineHandlers": {
    "FileParserHandler": ["SplitTextHandler"], // 表示文件解析完成后交由文本切分处理器SplitTextHandler进行处理
    "SplitTextHandler": ["TextEmbeddingHandler"],
    "TextEmbeddingHandler": ["ImageEmbeddingHandler"],
    "ImageEmbeddingHandler": []
    }
    }],
    "knowledgeProcess": {
    "embeddingModelCfg":
    {
    "modelVersion": "default" // 向量表征模型,"default" 表示默认版本
    },
    "chunkSplitter":
    {
    "chunkSize": 3072,
    "segmentSize": 300,
    "overlapRatio": 0.1
    },
    "perRecordLimit":
    {
    "parseFileMaxCnt": 10,
    "textEmbeddingMaxCnt": 50,
    "imageEmbeddingMaxCnt": 10
    }
    }
    }]
    }
    字段是否可选说明
    versionschema的版本号,正整数,最大值为2147483647。
    dbName数据库名称,最小长度为1,最大长度为120,支持数字、大小写字母、下划线和字符“.”。
    tableName知识表名称,最小长度为1,最大长度为120,支持数字、大小写字母和下划线。
    columnName知识字段列名,最小长度为1,最大长度为255。
    referenceFields知识表主键,仅支持一个字段,且字段为整数类型,字段值最小长度为1,最大长度为255。
    type知识字段类型,支持的知识字段类型,包括: - Text:纯文本知识加工字段。 - Scalar:标量字段。 必须包含description字段,字段取值范围:[1,255]。 Scalar字段不会进行知识加工,内容与业务表对应字段保持一致。 Scalar字段的columnName允许长度范围:[1, 128]。 - Json:Json格式的知识加工字段。 必须包含parser字段,用于指定文件路径的解析器。 每个Json字段允许定义的parser数量范围是[1, 5],最多支持提取5个不同的本地文件路径。 每个parser对象必填type和path,其中type为File,path的长度范围是[1,255]。 path必须是合法的Json路径表达式,用于表示知识加工需要解析的文件路径。 - Markdown: Markdown格式的知识加工字段。当前仅支持一个Markdown类型的知识字段,且Markdown字段不能同时设置为其它类型。起始版本: 6.1.0(23)
    processSequence加工顺序,用于定义数据的加工顺序,包含columnName和sortType两个字段。 - columnName对应一个数据源表的列名。 columnName值的长度范围是[1,255],支持数字、大小写字母和下划线。 columnName对应的列必须是整数类型,且必须在数据源表里存在。 - sortType用于指定升序或降序排列。 sortType仅能配置为"ASC"(升序)或"DESC"(降序)。
    customKeyword自定义关键字,用于配置关键字提取功能。配置该字段后知识加工会额外生成关键字表,表名相比数据源表增加"_knowledge_keyword"后缀,包含三个字段。 - wordTablePath对应关键词列表文件的路径,长度范围是[1, 255],文件必须是.txt类型且实际存在。 - sourceFields用于指定关键词提取功能生效的列,长度范围[1, 10]。其中每个列的长度范围是[1, 255],且只能包含数字、大小写字母和下划线。 - extendFields用于指定关键字提取产物额外需要创建的列,长度范围[0, 10]。其中每个列的长度范围是[1, 255],且只能包含数字、大小写字母和下划线。 起始版本: 6.1.0(23)
    commonAttribute公共特征,当前仅支持配置时间特征,对应字段为"time"。配置该字段后知识加工会额外生成时间表,表名相比数据源表增加"_knowledge_time"后缀, 包含三个字段。 - baseTimeField对应基准时间列,长度范围是[1, 255]且该列实际存在。该列在数据源表中需要是合法的Unix毫秒级时间戳。 - sourceFields用于指定时间特征提取功能生效的列,长度范围[1, 10]。其中每个列的长度范围是[1, 255],且只能包含数字、大小写字母和下划线。 - extendFields用于指定时间特征提取产物额外需要创建的列,长度范围[0, 10]。其中每个列的长度范围是[1, 255],且只能包含数字、大小写字母和下划线。 起始版本: 6.1.0(23)
    pipelineHandlers执行顺序,用于定义知识加工时各处理模块(Handler)的执行顺序,可以控制原始数据如何被解析、切分、表征,最终写入倒排表与向量表。 可修改Handler流程,配置为一个映射(unordered_map<string, vector<string>>),每个键为当前Handler,值为其后续执行的Handler列表,参考示例: "pipelineHandlers": { "FileParserHandler": ["SplitTextHandler"], "SplitTextHandler": ["TextEmbeddingHandler"], "TextEmbeddingHandler": ["ImageEmbeddingHandler"], "ImageEmbeddingHandler": [] } 当前Handler支持的名称包括:FileParserHandler、SplitTextHandler、TextEmbeddingHandler、ImageEmbeddingHandler。 Handler之间不能出现循环依赖,否则系统会在加载schema时报错。 每个Handler的下游可以为空数组,表示加工流程在此结束。 推荐的标准知识加工流程为: FileParserHandler → SplitTextHandler → TextEmbeddingHandler → ImageEmbeddingHandler。 如果配置顺序错误(如跳过某些处理器、顺序不通或形成闭环),可能导致文件未处理、加工流程中断或初始化失败。 可根据实际场景适当简化,例如:仅加工倒排索引时只配置SplitTextHandler。 各Handler功能与依赖说明如下: - FileParserHandler:提取Json字段中指向本地文件的文本内容,支持格式:doc、docx、ppt、pptx、xls、xlsx、html、txt、pdf、png、jpg、jpeg。文本类文件会提取正文内容,图片文件会通过OCR提取可识别文本。不依赖其他Handler。 推荐组合:建议放在SplitTextHandler之前,使提取出的文件内容能被切分、表征。 未配置影响:Json字段内文件不会被解析,倒排和向量中均无这些内容(不影响图片向量表征)。 - SplitTextHandler:对文本字段进行两级切分。 - 第一级chunk:用于倒排索引 - 第二级segment:用于向量表征(Embedding) 推荐组合:必须在TextEmbeddingHandler之前;否则向量表征阶段缺少segment,后续表征失败。 未配置影响:倒排表和向量表都无文本内容,检索无法返回文本相关内容。 - TextEmbeddingHandler:对SplitTextHandler产生的segment进行文本向量表征,生成供向量检索使用的数据。依赖SplitTextHandler的结果。 推荐组合:放在SplitTextHandler之后、ImageEmbeddingHandler 之前。 未配置影响:文本表征结果不会进入向量表,影响语义搜索。 - ImageEmbeddingHandler:根据Json字段解析后的图像路径加载图片,并对图像特征进行向量表征。图片处理不依赖SplitTextHandler和TextEmbeddingHandler,也不会参与文本倒排表,独立于文本处理流程。 推荐组合:放在TextEmbeddingHandler之后,避免图片路径字段被误当作文本参与表征,产生噪声。 未配置影响:图像表征结果不会进入向量表,影响图片相关搜索。
    knowledgeProcess加工参数,用于设置知识加工参数配置,开发者可根据实际情况选择一个或多个字段进行配置。配置对应字段后,对应的子字段内部的内容均为必填,不允许部分配置。包括以下三个字段。 - embeddingModelCfg:表征模型设置。 若knowledgeProcess中配置了embeddingModelCfg字段,则必须包含modelVersion字段,类型为字符串,表示所使用的向量表征模型版本。 字段值最大长度为100,若为空字符串会使用默认版本。 该字段值需与实际部署或支持的模型版本匹配,且知识加工的表征模型版本需要和推理的版本一致,当前默认值为"default"。 - chunkSplitter:文本切分设置。 若knowledgeProcess字段中配置了chunkSplitter字段,则需同时配置以下三个子字段,均为必填项。 - chunkSize:每个Chunk的最大长度,整数类型,取值范围为[100, 5000],默认值为3072。 - segmentSize:Chunk内部分段的最大长度,是向量表征的单位,整数类型,取值范围为[128, 512],默认值为300。 - overlapRatio:相邻Chunk之间的重叠比例,浮点数类型,取值范围为(0.0, 0.3],默认值为0.1。 这些参数用于控制文本切分策略,影响切分粒度、上下文连续性,如果未配置,则系统将使用上述默认值。 - perRecordLimit:文件预处理限制。 若knowledgeProcess中配置了perRecordLimit字段,则需同时配置以下三个字段,均为必填项。 - parseFileMaxCnt:每条记录最多允许解析的文件数,整数类型,取值范围为[0, 200],默认值为10。 - textEmbeddingMaxCnt:每条记录最多进行向量表征的文本段数量,整数类型,取值范围为[0, 200],默认值为50,超出限制的文本段不会被表征。 - imageEmbeddingMaxCnt:每条记录最多进行处理的图片数量,整数类型,取值范围为[0, 200],默认值为10。 这些参数用于限制单条记录在知识加工过程中的最大处理规模,如果未配置,则系统将采用默认值。
  2. 配置数据源库开库参数,根据业务需要预置数据。下文是示例代码片段,仅供参考,具体实现方式请根据业务需要调整。

    schema示例中inline_files列配置的type为Json,且其path字段为指向uri的路径表达式,那么知识加工会去数据库中的inline_files字段解析uri对应的值作为文件路径。插入数据的SQL语句inline_files列的值应配置为示例代码中所示的文件路径的对象数组形式。加工时会根据获取的文件路径进行知识构建。

    • relationalStore开库参数配置中的name字段需要与中"dbName"字段保持一致,并且enableSemanticIndex字段需要设置为true才会触发知识加工。
    • 建表语句中的表名需要与中"tableName"字段保持一致,列名与"columnName"字段保持一致。
    import { relationalStore } from '@kit.ArkData';

    // relationalStore开库参数配置
    const storeConfig: relationalStore.StoreConfig = {
    name: 'testmail_store.db', // 注意与步骤1中"dbName"字段保持一致
    securityLevel: relationalStore.SecurityLevel.S3,
    enableSemanticIndex: true, // 注意该项设为true才会触发知识加工
    tokenizer: relationalStore.Tokenizer.CUSTOM_TOKENIZER
    };

    // 建表语句,注意表名应与步骤1中"tableName"字段保持一致,列名与"columnName"字段保持一致
    const createTableSql = "CREATE TABLE IF NOT EXISTS email(id integer primary key, subject text, " +
    "content text, image_text text, attachment_names text, inline_files text, sender text, " +
    "receivers text, received_date text);";

    // 插入数据语句,请按实际业务需要实现,下文仅作参考
    const sql = `insert or replace into email VALUES(0, 'Subject of an email', 'Content of an email', 'Convert image to text through OCR',
    'attachment_name_1.txt, attachment_name_2.txt', '[{"uri":"/data/storage/el2/base/haps/entry/files/capture_1.png"},{"uri":"/data/storage/el2/base/haps/entry/files/capture_2.jpeg"}]',
    'test1(test1@example.com)', 'test2(test2@example.com), test3(test3@example.com)', 'Convert time to timestamp');`;
  3. 可根据业务需要,调用getStatus()接口,查询当前的知识加工状态。

    import { relationalStore } from '@kit.ArkData';
    import { knowledgeProcessor } from '@kit.DataAugmentationKit';
    import { UIAbility, common } from '@kit.AbilityKit';

    // relationalStore开库参数配置
    const storeConfig: relationalStore.StoreConfig = {
    name: 'testmail_store.db', // 注意与步骤1中"dbName"字段保持一致
    securityLevel: relationalStore.SecurityLevel.S3,
    enableSemanticIndex: true,
    tokenizer: relationalStore.Tokenizer.CUSTOM_TOKENIZER
    };

    let knowledgeSourceConfig: knowledgeProcessor.KnowledgeSourceConfig = {
    rdbSource: storeConfig,
    }
    let knowledgeProcessorConfig: knowledgeProcessor.KnowledgeProcessorConfig = {
    sourceConfig: knowledgeSourceConfig,
    }

    // 获取知识加工状态的异步函数,业务自行按需调用
    async function getStatus() {
    const context = AppStorage.get<common.UIAbilityContext>("Context") as common.UIAbilityContext;
    try {
    // 获取知识加工对象
    const processor = await knowledgeProcessor.getKnowledgeProcessor(context, knowledgeProcessorConfig);
    // 获取知识加工状态
    const status: knowledgeProcessor.ProcessorStatus = await processor.getStatus();
    return status;
    } catch (err) {
    console.error("Error: " + err.message + " code: " + err.code);
    return undefined;
    }
    }
  4. 可根据业务需要,调用startProcess(option: KnowledgeProcessConfig)接口,启动知识加工。

    import { relationalStore } from '@kit.ArkData';
    import { knowledgeProcessor } from '@kit.DataAugmentationKit';
    import { UIAbility, common } from '@kit.AbilityKit';

    // relationalStore开库参数配置
    const storeConfig: relationalStore.StoreConfig = {
    name: 'testmail_store.db', // 注意与步骤1中"dbName"字段保持一致
    securityLevel: relationalStore.SecurityLevel.S3,
    enableSemanticIndex: true,
    tokenizer: relationalStore.Tokenizer.CUSTOM_TOKENIZER
    };

    let knowledgeSourceConfig: knowledgeProcessor.KnowledgeSourceConfig = {
    rdbSource: storeConfig,
    }
    let knowledgeProcessorConfig: knowledgeProcessor.KnowledgeProcessorConfig = {
    sourceConfig: knowledgeSourceConfig,
    }

    // 启动知识加工的异步函数,业务自行按需调用
    async function startProcess() {
    const context = AppStorage.get<common.UIAbilityContext>("Context") as common.UIAbilityContext;
    try {
    // 获取知识加工对象
    const processor = await knowledgeProcessor.getKnowledgeProcessor(context, knowledgeProcessorConfig);
    // 启动知识加工
    let processMode: knowledgeProcessor.KnowledgeProcessMode = knowledgeProcessor.KnowledgeProcessMode.INVERTED_INDEX;
    let config: knowledgeProcessor.KnowledgeProcessConfig = {
    mode: processMode,
    }
    await processor.startProcess(config);
    } catch (err) {
    console.error("Error: " + err.message + " code: " + err.code);
    }
    }
  5. 可根据业务需要,调用stopProcess()接口,停止知识加工。

    import { relationalStore } from '@kit.ArkData';
    import { knowledgeProcessor } from '@kit.DataAugmentationKit';
    import { UIAbility, common } from '@kit.AbilityKit';

    // relationalStore开库参数配置
    const storeConfig: relationalStore.StoreConfig = {
    name: 'testmail_store.db', // 注意与步骤1中"dbName"字段保持一致
    securityLevel: relationalStore.SecurityLevel.S3,
    enableSemanticIndex: true,
    tokenizer: relationalStore.Tokenizer.CUSTOM_TOKENIZER
    };

    let knowledgeSourceConfig: knowledgeProcessor.KnowledgeSourceConfig = {
    rdbSource: storeConfig,
    }
    let knowledgeProcessorConfig: knowledgeProcessor.KnowledgeProcessorConfig = {
    sourceConfig: knowledgeSourceConfig,
    }

    // 停止知识加工的异步函数,业务自行按需调用
    async function stopProcess() {
    const context = AppStorage.get<common.UIAbilityContext>("Context") as common.UIAbilityContext;
    try {
    // 获取知识加工对象
    const processor = await knowledgeProcessor.getKnowledgeProcessor(context, knowledgeProcessorConfig);
    // 停止知识加工
    await processor.stopProcess();
    } catch (err) {
    console.error("Error: " + err.message + " code: " + err.code);
    }
    }
  6. 可根据业务需要,调用cleanKnowledgeData(context: common.BaseContext, config: KnowledgeProcessorConfig)接口,将知识库进行清理。注意:看约束和限制说明使用。

    import { relationalStore } from '@kit.ArkData';
    import { knowledgeProcessor } from '@kit.DataAugmentationKit';
    import { UIAbility, common } from '@kit.AbilityKit';

    // relationalStore开库参数配置
    const storeConfig: relationalStore.StoreConfig = {
    name: 'testmail_store.db', // 注意与步骤1中"dbName"字段保持一致
    securityLevel: relationalStore.SecurityLevel.S3,
    enableSemanticIndex: true,
    tokenizer: relationalStore.Tokenizer.CUSTOM_TOKENIZER
    };

    let knowledgeSourceConfig: knowledgeProcessor.KnowledgeSourceConfig = {
    rdbSource: storeConfig,
    }
    let knowledgeProcessorConfig: knowledgeProcessor.KnowledgeProcessorConfig = {
    sourceConfig: knowledgeSourceConfig,
    }

    // 清理知识库的异步函数,业务自行按需调用
    async function cleanKnowledgeData() {
    const context = AppStorage.get<common.UIAbilityContext>("Context") as common.UIAbilityContext;
    try {
    // 清理知识库
    await knowledgeProcessor.cleanKnowledgeData(context, knowledgeProcessorConfig);
    } catch (err) {
    console.error("Error: " + err.message + " code: " + err.code);
    }
    }