Azure 认知搜索 DocumentExtractionSkill 无法提取文本?
2025-03-19 05:33:26
Azure 认知搜索中 DocumentExtractionSkill 无法从 Blob 数据提取文本的问题解决
在使用 Azure 认知搜索时, 遇到 DocumentExtractionSkill
不能从数据库的 VARBINARY(MAX)
类型字段中正确提取 PDF 等文件内容的现象,挺常见的。就是明明配置好了索引、技能集和索引器,但索引结果里的 content
和 metadata
字段却是空的。 别急, 下面咱们一起分析原因并给出解决办法。
一、 问题原因分析
问题出在认知搜索服务如何访问和处理数据源上。当前配置, 索引器直接尝试从SQL 数据库读取 FileData
(VARBINARY(MAX) 数据),但 DocumentExtractionSkill
的设计初衷是从Azure Blob 存储提取内容,而不是直接从SQL SERVER BLOB列。认知搜索不能直接“理解”数据库中存储的原始二进制数据。
我们需要一个桥梁,让认知搜索能识别和处理数据库中的二进制文件数据。
二、解决方案
要解决这个问题,关键在于把SQL数据库中的二进制数据,变成认知搜索能处理的格式。有以下几种方法:
1. 利用 Azure Blob 存储作为中间层
这是推荐的方法,也是最直接的方法。 认知搜索本来就擅长处理Blob存储的数据。
-
原理: 将 SQL Server 中的文件数据导出到 Azure Blob 存储, 然后配置认知搜索从 Blob 存储提取内容。
-
步骤:
-
创建 Azure Blob 存储账户和容器。 这个不用多说,在Azure门户里点几下鼠标就搞定。
-
将数据导出到 Blob 存储。 可以写一个简单的程序(例如 C# 或 Python)或者用Azure Data Factory从 SQL Server 读取
FileData
,然后将每个文件上传到 Blob 存储的容器中。确保文件名唯一,可以用数据库里的ID
或FileName
。// C# 代码示例 (需要安装 Azure.Storage.Blobs NuGet 包) using Azure.Storage.Blobs; using System.Data.SqlClient; // ... 省略其他代码 string connectionString = "你的 SQL Server 连接字符串"; string blobConnectionString = "你的 Blob 存储连接字符串"; string containerName = "你的 Blob 容器名"; BlobServiceClient blobServiceClient = new BlobServiceClient(blobConnectionString); BlobContainerClient containerClient = blobServiceClient.GetBlobContainerClient(containerName); using (SqlConnection connection = new SqlConnection(connectionString)) { connection.Open(); string query = "SELECT ID, FileName, FileData FROM FileStorage"; using (SqlCommand command = new SqlCommand(query, connection)) { using (SqlDataReader reader = command.ExecuteReader()) { while (reader.Read()) { int id = reader.GetInt32(0); string fileName = reader.GetString(1); byte[] fileData = (byte[])reader.GetValue(2); // 使用唯一的文件名 (例如,ID + 文件名) string blobName =
quot;{id}_{fileName}"; BlobClient blobClient = containerClient.GetBlobClient(blobName); //分块上传 using (var stream = new MemoryStream(fileData)) blobClient.Upload(stream,overwrite:true); //直接上传 //blobClient.Upload(new BinaryData(fileData)); } } } }// C# 代码示例 (需要安装 Azure.Storage.Blobs NuGet 包) using Azure.Storage.Blobs; using System.Data.SqlClient; // ... 省略其他代码 string connectionString = "你的 SQL Server 连接字符串"; string blobConnectionString = "你的 Blob 存储连接字符串"; string containerName = "你的 Blob 容器名"; BlobServiceClient blobServiceClient = new BlobServiceClient(blobConnectionString); BlobContainerClient containerClient = blobServiceClient.GetBlobContainerClient(containerName); using (SqlConnection connection = new SqlConnection(connectionString)) { connection.Open(); string query = "SELECT ID, FileName, FileData FROM FileStorage"; using (SqlCommand command = new SqlCommand(query, connection)) { using (SqlDataReader reader = command.ExecuteReader()) { while (reader.Read()) { int id = reader.GetInt32(0); string fileName = reader.GetString(1); byte[] fileData = (byte[])reader.GetValue(2); // 使用唯一的文件名 (例如,ID + 文件名) string blobName = $"{id}_{fileName}"; BlobClient blobClient = containerClient.GetBlobClient(blobName); //分块上传 using (var stream = new MemoryStream(fileData)) blobClient.Upload(stream,overwrite:true); //直接上传 //blobClient.Upload(new BinaryData(fileData)); } } } }
-
修改认知搜索配置。
- 数据源 (Data Source): 指向 Azure Blob 存储容器。
- 在“数据源”配置中,指定 “类型” 为 “Azure Blob 存储”,提供连接字符串。
- 在"解析模式"那里,选择 "DetectAllText (为PDF和其他结构化或半结构化内容建议选择的项)".
- 技能集 (Skillset): 保持
DocumentExtractionSkill
的配置不变,或者微调parsingMode
和dataToExtract
参数。 - 索引器 (Indexer): 修改
fieldMappings
,从 Blob 存储中的字段映射到索引中的字段。例如,"sourceFieldName": "/document/content"
对应 Blob 中的文件内容。 - 关键配置, 将sourceFieldName指向blob:
```json "fieldMappings": [ { "sourceFieldName": "metadata_storage_name", "targetFieldName": "fileName" }, { "sourceFieldName": "metadata_storage_path", "targetFieldName": "id", "mappingFunction":{ "name":"base64Encode" } } ], "outputFieldMappings": [ { "sourceFieldName": "/document/content", "targetFieldName": "content" }, { "sourceFieldName": "/document/metadata", "targetFieldName": "metadata" } ] ```
- 将ID 字段使用base64编码。
- 这里面的
metadata_storage_name
对应数据库表里的fileName
,认知搜索能自己提取到.
-
运行索引器。 重新运行索引器,它将从 Blob 存储读取文件,提取文本并填充到索引的
content
字段。
-
-
安全建议:
- 使用托管标识 (Managed Identities) 进行身份验证,避免在代码或配置中存储密钥。
- 对 Blob 存储进行加密(静态加密和服务端加密)。
- 使用网络安全组 (NSGs) 或防火墙限制对 Blob 存储的访问。
2. 自定义技能 (Custom Skill)
如果你不想使用 Azure Blob 存储, 或者有特殊处理需求,可以考虑创建自定义技能。
-
原理: 自定义技能本质上是一个 Web API,它接收来自认知搜索的数据,进行处理,然后返回处理后的结果。 你可以在自定义技能中实现从 SQL Server 读取二进制数据、提取文本的逻辑。
-
步骤:
- 创建 Web API。 可以使用 Azure Functions 或任何其他 Web API 框架(例如 ASP.NET Core)。这个 API 需要接收包含
FileData
的请求,提取文本(可以使用 iTextSharp 或 PdfSharp 等库处理 PDF),然后返回包含content
和metadata
的响应。 - 部署 Web API。 将 Web API 部署到 Azure 或任何其他可公开访问的环境。
- 配置认知搜索。
-
技能集 (Skillset): 添加一个自定义技能,指定 Web API 的 URL 和认证信息(如果需要)。
inputs
部分应该包含file_data
,outputs
部分包含content
和metadata
。{ "@odata.type": "#Microsoft.Skills.Custom.WebApiSkill", "name": "customSkill", "description": "Custom skill to extract text from SQL Server data", "context": "/document", "uri": "你的 Web API 的 URL", "httpHeaders": {}, // 如果需要,添加请求头 "httpMethod": "POST", "timeout": "PT30S", "batchSize": 1, "inputs": [ { "name": "file_data", "source": "/document/file_data" } ], "outputs": [ { "name": "content", "targetName": "content" }, { "name": "metadata", "targetName": "metadata" } ] }
-
索引器 (Indexer):
fieldMappings
和outputFieldMappings
与原来类似,但要确保outputFieldMappings
中的sourceFieldName
指向自定义技能的输出 (/document/content
和/document/metadata
)。
-
- 运行索引器。 运行索引器,认知搜索会调用你的自定义技能来提取数据。
- 创建 Web API。 可以使用 Azure Functions 或任何其他 Web API 框架(例如 ASP.NET Core)。这个 API 需要接收包含
-
进阶: 如果数据量非常大, 可以在自定义技能中使用异步处理和批处理, 提高效率。
-
安全建议:
- 使用HTTPS。
- 使用API密钥或其他身份验证机制保护 Web API。
3.(不建议,有局限)直接在认知搜索数据源中配置转换
在某些情况下,如果你只处理文本类的数据库内容,并且不需要保留文件原本的二进制格式,可以直接在认知搜索数据源中配置转换, 比如直接将varbinary(max) cast为varchar(max), 让认知搜索尝试把二进制当成字符串。
-
只适合处理简单文本情况,对于 PDF 这类非纯文本, 无效.
-- 修改数据源的查询,将 FileData 转换为 VARCHAR(MAX) -- 适用于纯文本内容,或者你知道内容是UTF8,Latin1之类的编码。 -- SELECT ID, FileName, CAST(FileData AS VARCHAR(MAX)) AS FileContent, UploadDate FROM FileStorage -- 对应的FiledMapping 要做更改 "fieldMappings": [ { "sourceFieldName": "fileContent", "targetFieldName": "content" } ]
- 需要修改对应索引器,和字段对应.
-
只能针对纯文本格式的文件有效,如果是PDF之类的,会得到一堆乱码.
三、总结和选择
- 首推Azure Blob 存储 作为中间媒介的方法,符合认知搜索的常见用法,配置和操作简单,性能也好。
- 如果有很特殊的要求,例如数据不能放到Blob,必须实时从数据库读取和处理,需要做复杂的数据转换, 可以选择自定义技能,但开发和维护成本会高一些。
- 第三种,数据源直接转换,仅仅能处理纯文本类型文件,实际情况局限太大,不建议。
记住,无论选择哪种方法,关键都是为认知搜索的 DocumentExtractionSkill
提供它可以处理的输入数据。 通过以上这些步骤和分析,应该能解决你遇到的问题,让认知搜索正确提取到文件内容。