feat: 集成Eino文档解析与嵌入功能
新增Eino相关依赖,支持docx、pdf、xlsx等格式的文档加载与解析,并集成了Dashscope嵌入模型。同时修复了部分DAO查询中的OmitEmpty配置。
This commit is contained in:
@@ -86,7 +86,11 @@ func (d *BaseDataSource) Connect(ctx context.Context) error {
|
||||
defer d.mu.Unlock()
|
||||
|
||||
// 构建客户端
|
||||
d.client = ms.New(d.config.Host, ms.WithAPIKey(d.config.APIKey))
|
||||
host := d.config.Host
|
||||
if d.config.Port > 0 {
|
||||
host = fmt.Sprintf("%s:%d", d.config.Host, d.config.Port)
|
||||
}
|
||||
d.client = ms.New(host, ms.WithAPIKey(d.config.APIKey))
|
||||
|
||||
// 测试连接
|
||||
if err := d.healthCheck(ctx); err != nil {
|
||||
|
||||
@@ -71,22 +71,97 @@ func (m *meilisearchDB) getDataSource() (DataSource, error) {
|
||||
}
|
||||
|
||||
// getClient 获取 Meilisearch 客户端
|
||||
func (m *meilisearchDB) getClient() (interface{ Index(string) interface{} }, error) {
|
||||
func (m *meilisearchDB) getClient() (ms.ServiceManager, error) {
|
||||
source, err := m.getDataSource()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if c, ok := source.Client().(interface{ Index(string) interface{} }); ok {
|
||||
if c, ok := source.Client().(ms.ServiceManager); ok {
|
||||
return c, nil
|
||||
}
|
||||
return nil, fmt.Errorf("invalid client type")
|
||||
}
|
||||
|
||||
// indexInterface 辅助函数,获取index
|
||||
func indexInterface(indexName string, client interface{ Index(string) interface{} }) interface{} {
|
||||
func indexInterface(indexName string, client ms.ServiceManager) ms.IndexManager {
|
||||
return client.Index(indexName)
|
||||
}
|
||||
|
||||
// ensureIndexExists 确保索引存在,不存在则自动创建
|
||||
// 同时会检查并更新 filterable attributes 设置
|
||||
func (m *meilisearchDB) ensureIndexExists(client ms.ServiceManager, indexName string) error {
|
||||
// 使用 Index 方法获取索引(不存在时不会报错)
|
||||
idx := client.Index(indexName)
|
||||
|
||||
// 先获取索引信息,检查是否存在
|
||||
_, err := idx.FetchInfo()
|
||||
if err != nil {
|
||||
// 索引不存在,创建索引并等待完成
|
||||
task, err := client.CreateIndex(&ms.IndexConfig{
|
||||
Uid: indexName,
|
||||
PrimaryKey: "id",
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 等待索引创建完成(最多等待10秒)
|
||||
if _, err = client.WaitForTask(task.TaskUID, 10*time.Second); err != nil {
|
||||
return fmt.Errorf("等待索引创建失败: %w", err)
|
||||
}
|
||||
// 重新获取索引
|
||||
idx = client.Index(indexName)
|
||||
}
|
||||
|
||||
// 检查并更新 filterable attributes
|
||||
settings, err := idx.GetSettings()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
requiredFilterable := []string{"tenantId", "isDeleted", "datasetId", "creator", "updater"}
|
||||
needUpdate := false
|
||||
|
||||
// 检查是否缺少必要的 filterable attributes
|
||||
existingFilterable := make(map[string]bool)
|
||||
for _, attr := range settings.FilterableAttributes {
|
||||
existingFilterable[attr] = true
|
||||
}
|
||||
|
||||
for _, attr := range requiredFilterable {
|
||||
if !existingFilterable[attr] {
|
||||
needUpdate = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if needUpdate {
|
||||
// 合并现有的 filterable attributes 和新增的
|
||||
allFilterable := append(settings.FilterableAttributes, requiredFilterable...)
|
||||
uniqueFilterable := make(map[string]bool)
|
||||
var finalFilterable []string
|
||||
for _, attr := range allFilterable {
|
||||
if !uniqueFilterable[attr] {
|
||||
uniqueFilterable[attr] = true
|
||||
finalFilterable = append(finalFilterable, attr)
|
||||
}
|
||||
}
|
||||
|
||||
updateSettings := &ms.Settings{
|
||||
FilterableAttributes: finalFilterable,
|
||||
}
|
||||
task, err := idx.UpdateSettings(updateSettings)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 等待设置更新完成(最多等待10秒)
|
||||
if _, err = client.WaitForTask(task.TaskUID, 10*time.Second); err != nil {
|
||||
return fmt.Errorf("等待设置更新失败: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// buildSearchRequest 构建搜索请求
|
||||
func (m *meilisearchDB) buildSearchRequest(ctx context.Context, searchParams *SearchParams) (*ms.SearchRequest, error) {
|
||||
user, err := utils.GetUserInfo(ctx)
|
||||
@@ -154,13 +229,18 @@ func (m *meilisearchDB) buildSearchRequest(ctx context.Context, searchParams *Se
|
||||
return req, nil
|
||||
}
|
||||
|
||||
// Search 搜索文档
|
||||
// Search 搜索文档(索引不存在时返回空结果)
|
||||
func (m *meilisearchDB) Search(ctx context.Context, searchParams *SearchParams, indexName string, result interface{}) (total int64, err error) {
|
||||
client, err := m.getClient()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// 检查索引是否存在,不存在则返回空结果
|
||||
if _, err = client.GetIndex(indexName); err != nil {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// 构建搜索请求
|
||||
req, err := m.buildSearchRequest(ctx, searchParams)
|
||||
if err != nil {
|
||||
@@ -201,14 +281,7 @@ func (m *meilisearchDB) Search(ctx context.Context, searchParams *SearchParams,
|
||||
|
||||
// 执行搜索
|
||||
idx := indexInterface(indexName, client)
|
||||
var searchResp *ms.SearchResponse
|
||||
if i, ok := idx.(interface {
|
||||
Search(string, *ms.SearchRequest) (*ms.SearchResponse, error)
|
||||
}); ok {
|
||||
searchResp, err = i.Search(searchParams.Query, req)
|
||||
} else {
|
||||
return 0, fmt.Errorf("index does not support Search method")
|
||||
}
|
||||
searchResp, err := idx.Search(searchParams.Query, req)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -261,13 +334,18 @@ func (m *meilisearchDB) Search(ctx context.Context, searchParams *SearchParams,
|
||||
return
|
||||
}
|
||||
|
||||
// Insert 插入文档
|
||||
// Insert 插入文档(自动创建索引)
|
||||
func (m *meilisearchDB) Insert(ctx context.Context, document interface{}, indexName string) (taskUID int64, err error) {
|
||||
c, err := m.getClient()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// 确保索引存在
|
||||
if err = m.ensureIndexExists(c, indexName); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
user, err := utils.GetUserInfo(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
@@ -308,14 +386,7 @@ func (m *meilisearchDB) Insert(ctx context.Context, document interface{}, indexN
|
||||
// 执行插入
|
||||
documents := []map[string]interface{}{docMap}
|
||||
idx := indexInterface(indexName, c)
|
||||
var task *ms.TaskInfo
|
||||
if i, ok := idx.(interface {
|
||||
AddDocuments([]map[string]interface{}, interface{}) (*ms.TaskInfo, error)
|
||||
}); ok {
|
||||
task, err = i.AddDocuments(documents, nil)
|
||||
} else {
|
||||
return 0, fmt.Errorf("index does not support AddDocuments method")
|
||||
}
|
||||
task, err := idx.AddDocuments(documents, nil)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -329,13 +400,18 @@ func (m *meilisearchDB) Insert(ctx context.Context, document interface{}, indexN
|
||||
return task.TaskUID, nil
|
||||
}
|
||||
|
||||
// InsertMany 批量插入文档
|
||||
// InsertMany 批量插入文档(自动创建索引)
|
||||
func (m *meilisearchDB) InsertMany(ctx context.Context, documents []interface{}, indexName string) (taskUID int64, err error) {
|
||||
c, err := m.getClient()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// 确保索引存在
|
||||
if err = m.ensureIndexExists(c, indexName); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
user, err := utils.GetUserInfo(ctx)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
@@ -379,14 +455,7 @@ func (m *meilisearchDB) InsertMany(ctx context.Context, documents []interface{},
|
||||
|
||||
// 执行批量插入
|
||||
idx := indexInterface(indexName, c)
|
||||
var task *ms.TaskInfo
|
||||
if i, ok := idx.(interface {
|
||||
AddDocuments([]map[string]interface{}, interface{}) (*ms.TaskInfo, error)
|
||||
}); ok {
|
||||
task, err = i.AddDocuments(docs, nil)
|
||||
} else {
|
||||
return 0, fmt.Errorf("index does not support AddDocuments method")
|
||||
}
|
||||
task, err := idx.AddDocuments(docs, nil)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -426,14 +495,7 @@ func (m *meilisearchDB) Update(ctx context.Context, document interface{}, indexN
|
||||
// 执行更新
|
||||
documents := []map[string]interface{}{docMap}
|
||||
idx := indexInterface(indexName, c)
|
||||
var task *ms.TaskInfo
|
||||
if i, ok := idx.(interface {
|
||||
UpdateDocuments([]map[string]interface{}, interface{}) (*ms.TaskInfo, error)
|
||||
}); ok {
|
||||
task, err = i.UpdateDocuments(documents, nil)
|
||||
} else {
|
||||
return 0, fmt.Errorf("index does not support UpdateDocuments method")
|
||||
}
|
||||
task, err := idx.UpdateDocuments(documents, nil)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -456,14 +518,7 @@ func (m *meilisearchDB) Delete(ctx context.Context, id string, indexName string)
|
||||
|
||||
// 执行删除
|
||||
idx := indexInterface(indexName, c)
|
||||
var task *ms.TaskInfo
|
||||
if i, ok := idx.(interface {
|
||||
DeleteDocument(string) (*ms.TaskInfo, error)
|
||||
}); ok {
|
||||
task, err = i.DeleteDocument(id)
|
||||
} else {
|
||||
return 0, fmt.Errorf("index does not support DeleteDocument method")
|
||||
}
|
||||
task, err := idx.DeleteDocument(id, nil)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -504,14 +559,7 @@ func (m *meilisearchDB) DeleteSoft(ctx context.Context, id string, indexName str
|
||||
// 执行更新
|
||||
documents := []map[string]interface{}{updateMap}
|
||||
idx := indexInterface(indexName, c)
|
||||
var task *ms.TaskInfo
|
||||
if i, ok := idx.(interface {
|
||||
UpdateDocuments([]map[string]interface{}, interface{}) (*ms.TaskInfo, error)
|
||||
}); ok {
|
||||
task, err = i.UpdateDocuments(documents, nil)
|
||||
} else {
|
||||
return 0, fmt.Errorf("index does not support UpdateDocuments method")
|
||||
}
|
||||
task, err := idx.UpdateDocuments(documents, nil)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -552,13 +600,7 @@ func (m *meilisearchDB) Get(ctx context.Context, id string, indexName string, re
|
||||
// 执行查询
|
||||
var doc map[string]interface{}
|
||||
idx := indexInterface(indexName, c)
|
||||
if i, ok := idx.(interface {
|
||||
GetDocument(string, interface{}) error
|
||||
}); ok {
|
||||
err = i.GetDocument(id, &doc)
|
||||
} else {
|
||||
return fmt.Errorf("index does not support GetDocument method")
|
||||
}
|
||||
err = idx.GetDocument(id, nil, &doc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -600,122 +642,7 @@ func (m *meilisearchDB) cleanCache(ctx context.Context, indexName string, tenant
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateIndex 创建索引
|
||||
func (m *meilisearchDB) CreateIndex(ctx context.Context, indexConfig *IndexConfig) (taskUID int64, err error) {
|
||||
client, err := m.getClient()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
indexSettings := &ms.IndexConfig{
|
||||
Uid: indexConfig.UID,
|
||||
PrimaryKey: indexConfig.PrimaryKey,
|
||||
}
|
||||
|
||||
if c, ok := client.(interface {
|
||||
CreateIndex(*ms.IndexConfig) (*ms.TaskInfo, error)
|
||||
}); ok {
|
||||
task, err := c.CreateIndex(indexSettings)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return task.TaskUID, nil
|
||||
}
|
||||
return 0, fmt.Errorf("client does not support CreateIndex")
|
||||
}
|
||||
|
||||
// DeleteIndex 删除索引
|
||||
func (m *meilisearchDB) DeleteIndex(ctx context.Context, indexName string) (err error) {
|
||||
client, err := m.getClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c, ok := client.(interface{ DeleteIndex(string) error }); ok {
|
||||
return c.DeleteIndex(indexName)
|
||||
}
|
||||
return fmt.Errorf("client does not support DeleteIndex")
|
||||
}
|
||||
|
||||
// GetIndex 获取索引信息
|
||||
func (m *meilisearchDB) GetIndex(ctx context.Context, indexName string) (interface{}, error) {
|
||||
client, err := m.getClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if c, ok := client.(interface {
|
||||
GetIndex(string) (interface{}, error)
|
||||
}); ok {
|
||||
return c.GetIndex(indexName)
|
||||
}
|
||||
return nil, fmt.Errorf("client does not support GetIndex")
|
||||
}
|
||||
|
||||
// GetIndexes 获取所有索引
|
||||
func (m *meilisearchDB) GetIndexes(ctx context.Context) (interface{}, error) {
|
||||
client, err := m.getClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if c, ok := client.(interface {
|
||||
GetIndexes(interface{}) (interface{}, error)
|
||||
}); ok {
|
||||
return c.GetIndexes(nil)
|
||||
}
|
||||
return nil, fmt.Errorf("client does not support GetIndexes")
|
||||
}
|
||||
|
||||
// UpdateSettings 更新索引设置
|
||||
func (m *meilisearchDB) UpdateSettings(ctx context.Context, indexName string, settings *ms.Settings) (taskUID int64, err error) {
|
||||
c, err := m.getClient()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
idx := indexInterface(indexName, c)
|
||||
var task *ms.TaskInfo
|
||||
if i, ok := idx.(interface {
|
||||
UpdateSettings(*ms.Settings) (*ms.TaskInfo, error)
|
||||
}); ok {
|
||||
task, err = i.UpdateSettings(settings)
|
||||
} else {
|
||||
return 0, fmt.Errorf("index does not support UpdateSettings method")
|
||||
}
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return task.TaskUID, nil
|
||||
}
|
||||
|
||||
// GetSettings 获取索引设置
|
||||
func (m *meilisearchDB) GetSettings(ctx context.Context, indexName string) (*ms.Settings, error) {
|
||||
c, err := m.getClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
idx := indexInterface(indexName, c)
|
||||
var settings *ms.Settings
|
||||
if i, ok := idx.(interface{ GetSettings() (*ms.Settings, error) }); ok {
|
||||
settings, err = i.GetSettings()
|
||||
} else {
|
||||
return nil, fmt.Errorf("index does not support GetSettings method")
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return settings, nil
|
||||
}
|
||||
|
||||
// GetClient 获取原始客户端(用于高级操作)
|
||||
func (m *meilisearchDB) GetClient() (interface{ Index(string) interface{} }, error) {
|
||||
func (m *meilisearchDB) GetClient() (ms.ServiceManager, error) {
|
||||
return m.getClient()
|
||||
}
|
||||
|
||||
// BuildUpdateData 构建更新数据
|
||||
func BuildUpdateData(ctx context.Context, req interface{}) (map[string]interface{}, error) {
|
||||
return gconv.Map(req), nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user