mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-03-17 21:08:10 +08:00
Implement Search() in Infinity in GO (#13645)
### What problem does this PR solve? Implement Search() in Infinity in GO. The function can handle the following request. "search '曹操' on datasets 'infinity'" "search '常胜将军' on datasets 'infinity'" "search '卓越儒雅' on datasets 'infinity'" "search '辅佐刘禅北伐中原' on datasets 'infinity'" The output is exactly the same as request to python Search() ### Type of change - [ ] New Feature (non-breaking change which adds functionality)
This commit is contained in:
39
go.mod
39
go.mod
@ -3,11 +3,6 @@ module ragflow
|
||||
go 1.25
|
||||
|
||||
require (
|
||||
cloud.google.com/go/storage v1.35.1
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.4
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake v1.4.4
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.3
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.11
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.11
|
||||
@ -15,8 +10,8 @@ require (
|
||||
github.com/aws/smithy-go v1.24.2
|
||||
github.com/elastic/go-elasticsearch/v8 v8.19.1
|
||||
github.com/gin-gonic/gin v1.9.1
|
||||
github.com/go-sql-driver/mysql v1.7.0
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/infiniflow/infinity-go-sdk v0.0.0-00010101000000-000000000000
|
||||
github.com/iromli/go-itsdangerous v0.0.0-20220223194502-9c8bef8dac6a
|
||||
github.com/minio/minio-go/v7 v7.0.99
|
||||
github.com/peterh/liner v1.2.2
|
||||
@ -25,18 +20,12 @@ require (
|
||||
github.com/spf13/viper v1.18.2
|
||||
go.uber.org/zap v1.27.1
|
||||
golang.org/x/crypto v0.47.0
|
||||
google.golang.org/api v0.153.0
|
||||
gorm.io/driver/mysql v1.5.2
|
||||
gorm.io/gorm v1.25.5
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.110.10 // indirect
|
||||
cloud.google.com/go/compute v1.23.3 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.2.3 // indirect
|
||||
cloud.google.com/go/iam v1.1.5 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 // indirect
|
||||
github.com/apache/thrift v0.22.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.19 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.19 // indirect
|
||||
@ -66,13 +55,8 @@ require (
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.16.0 // indirect
|
||||
github.com/go-sql-driver/mysql v1.7.0 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/google/s2a-go v0.1.7 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.12.0 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
@ -80,7 +64,6 @@ require (
|
||||
github.com/klauspost/compress v1.18.2 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.11 // indirect
|
||||
github.com/klauspost/crc32 v1.3.0 // indirect
|
||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||
github.com/leodido/go-urn v1.2.4 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
@ -92,7 +75,7 @@ require (
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.1.1 // indirect
|
||||
github.com/philhofer/fwd v1.2.0 // indirect
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
|
||||
github.com/rogpeppe/go-internal v1.12.0 // indirect
|
||||
github.com/rs/xid v1.6.0 // indirect
|
||||
github.com/sagikazarmark/locafero v0.4.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
@ -100,11 +83,11 @@ require (
|
||||
github.com/spf13/afero v1.11.0 // indirect
|
||||
github.com/spf13/cast v1.6.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/stretchr/testify v1.11.1 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/tinylib/msgp v1.6.1 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.opentelemetry.io/otel v1.28.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.28.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.28.0 // indirect
|
||||
@ -114,18 +97,12 @@ require (
|
||||
golang.org/x/arch v0.6.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20231226003508-02704c960a9b // indirect
|
||||
golang.org/x/net v0.49.0 // indirect
|
||||
golang.org/x/oauth2 v0.15.0 // indirect
|
||||
golang.org/x/sync v0.19.0 // indirect
|
||||
golang.org/x/sys v0.41.0 // indirect
|
||||
golang.org/x/text v0.33.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f // indirect
|
||||
google.golang.org/grpc v1.59.0 // indirect
|
||||
google.golang.org/protobuf v1.32.0 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
replace github.com/infiniflow/infinity-go-sdk => github.com/infiniflow/infinity/go v0.0.0-20260317024756-4aff48d0d843
|
||||
|
||||
163
go.sum
163
go.sum
@ -1,33 +1,5 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.110.10 h1:LXy9GEO+timppncPIAZoOj3l58LIU9k+kn48AN7IO3Y=
|
||||
cloud.google.com/go v0.110.10/go.mod h1:v1OoFqYxiBkUrruItNM3eT4lLByNjxmJSV/xDKJNnic=
|
||||
cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk=
|
||||
cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI=
|
||||
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
|
||||
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
|
||||
cloud.google.com/go/iam v1.1.5 h1:1jTsCu4bcsNsE4iiqNT5SHwrDRCfRmIaaaVFhRveTJI=
|
||||
cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8=
|
||||
cloud.google.com/go/storage v1.35.1 h1:B59ahL//eDfx2IIKFBeT5Atm9wnNmj3+8xG/W4WB//w=
|
||||
cloud.google.com/go/storage v1.35.1/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0 h1:fou+2+WFTib47nS+nz/ozhEBnvU96bKHy6LjRsY4E28=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0/go.mod h1:t76Ruy8AHvUAC8GfMWJMa0ElSbuIcO03NLpynfbgsPA=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 h1:Hk5QBxZQC1jb2Fwj6mpzme37xbCDdNTxU7O9eb5+LB4=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1/go.mod h1:IYus9qsFobWIc2YVwe/WPjcnyCkPKtnHAqUYeebc8z0=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2/go.mod h1:Pa9ZNPuoNu/GztvBSKk9J1cDJW6vk/n0zLtV4mgd8N8=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 h1:9iefClla7iYpfYWdzPCRDozdmndjTm8DXdpCzPajMgA=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2/go.mod h1:XtLgD3ZD34DAaVIIAyG3objl5DynM3CQ/vMcbBNJZGI=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.8.1 h1:/Zt+cDPnpC3OVDm/JKLOs7M2DKmLRIIp3XIx9pHHiig=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.8.1/go.mod h1:Ng3urmn6dYe8gnbCMoHHVl5APYz2txho3koEkV2o2HA=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.4 h1:jWQK1GI+LeGGUKBADtcH2rRqPxYB1Ljwms5gFA2LqrM=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.4/go.mod h1:8mwH4klAm9DUgR2EEHyEEAQlRDvLPyg5fQry3y+cDew=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake v1.4.4 h1:7QtoGxKm6mPhsWzEZtrn3tQF1hmMMZblngnqNoE61I8=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake v1.4.4/go.mod h1:juYrzH1q6A+g9ZZbGh0OmjS7zaMq3rFDrPhVnYSgFMA=
|
||||
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM=
|
||||
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 h1:XRzhVemXdgvJqCH0sFfrBUTnUJSBrBf7++ypk+twtRs=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0/go.mod h1:HKpQxkWaGLJ+D/5H8QRpyQXA1eKjxkFlOMwck5+33Jk=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/apache/thrift v0.22.0 h1:r7mTJdj51TMDe6RtcmNdQxgn9XcyfGDOzegMDRg47uc=
|
||||
github.com/apache/thrift v0.22.0/go.mod h1:1e7J/O1Ae6ZQMTYdy9xa3w9k+XHWPfRvdPyJeynQ+/g=
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.3 h1:4kQ/fa22KjDt13QCy1+bYADvdgcxpfH18f0zP542kZA=
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.3/go.mod h1:mwsPRE8ceUUpiTgF7QmQIJ7lgsKUPQOUl3o72QBrE1o=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.6 h1:N4lRUXZpZ1KVEUn6hxtco/1d2lgYhNn1fHkkl8WhlyQ=
|
||||
@ -73,14 +45,11 @@ github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0
|
||||
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
||||
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
|
||||
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
@ -93,10 +62,6 @@ github.com/elastic/elastic-transport-go/v8 v8.8.0 h1:7k1Ua+qluFr6p1jfJjGDl97ssJS
|
||||
github.com/elastic/elastic-transport-go/v8 v8.8.0/go.mod h1:YLHer5cj0csTzNFXoNQ8qhtGY1GTvSqPnKWKaqQE3Hk=
|
||||
github.com/elastic/go-elasticsearch/v8 v8.19.1 h1:0iEGt5/Ds9MNVxEp3hqLsXdbe6SjleaVHONg/FuR09Q=
|
||||
github.com/elastic/go-elasticsearch/v8 v8.19.1/go.mod h1:tHJQdInFa6abmDbDCEH2LJja07l/SIpaGpJcm13nt7s=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||
@ -126,49 +91,15 @@ github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ
|
||||
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw=
|
||||
github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
|
||||
github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
|
||||
github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
|
||||
github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas=
|
||||
github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/infiniflow/infinity/go v0.0.0-20260317024756-4aff48d0d843 h1:s5g1APIXv4c6hwVL4+DwT5JDvRpegZpxxh2ltZzgeGE=
|
||||
github.com/infiniflow/infinity/go v0.0.0-20260317024756-4aff48d0d843/go.mod h1:hw3z5AwNFsGy1cdrE0Mfjot2y9jqVHTxBufUx9VzZ+0=
|
||||
github.com/iromli/go-itsdangerous v0.0.0-20220223194502-9c8bef8dac6a h1:Inib12UR9HAfBubrGNraPjKt/Cu8xPbTJbC50+0wP5U=
|
||||
github.com/iromli/go-itsdangerous v0.0.0-20220223194502-9c8bef8dac6a/go.mod h1:8N0Hlye5Lzw+H/yHWpZMkT0QLA+iOHG7KLdvAm95DZg=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
@ -177,8 +108,6 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU=
|
||||
github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k=
|
||||
github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk=
|
||||
github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
|
||||
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
@ -187,12 +116,13 @@ github.com/klauspost/cpuid/v2 v2.2.11 h1:0OwqZRYI2rFrjS4kvkDnqJkKHdHaRnCm68/DY4O
|
||||
github.com/klauspost/cpuid/v2 v2.2.11/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||
github.com/klauspost/crc32 v1.3.0 h1:sSmTt3gUt81RP655XGZPElI0PelVTZ6YwCRnPSupoFM=
|
||||
github.com/klauspost/crc32 v1.3.0/go.mod h1:D7kQaZhnkX/Y0tstFGf8VUzv2UofNGqCjnC3zdHB0Hw=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
|
||||
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
|
||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||
@ -220,12 +150,9 @@ github.com/peterh/liner v1.2.2 h1:aJ4AOodmL+JxOZZEL2u9iJf8omNRpqHc/EbrK+3mAXw=
|
||||
github.com/peterh/liner v1.2.2/go.mod h1:xFwJyiKIXJZUKItq5dGHZSTBRAuG/CpeNpWLyiNRNwI=
|
||||
github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM=
|
||||
github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM=
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/redis/go-redis/v9 v9.18.0 h1:pMkxYPkEbMPwRdenAzUNyFNrDgHx9U+DrBabWNfSRQs=
|
||||
github.com/redis/go-redis/v9 v9.18.0/go.mod h1:k3ufPphLU5YXwNTUcCRXGxUoF1fqxnhFQmscfkCoDA0=
|
||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
@ -270,8 +197,6 @@ github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65E
|
||||
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||
github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0=
|
||||
github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA=
|
||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||
go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo=
|
||||
go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4=
|
||||
go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q=
|
||||
@ -293,90 +218,18 @@ go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/arch v0.6.0 h1:S0JTfE48HbRj80+4tbvZDYsJ3tGv6BUU3XxyZ7CirAc=
|
||||
golang.org/x/arch v0.6.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8=
|
||||
golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20231226003508-02704c960a9b h1:kLiC65FbiHWFAOu+lxwNPujcsl8VYyTYYEZnsOO1WK4=
|
||||
golang.org/x/exp v0.0.0-20231226003508-02704c960a9b/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
|
||||
golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ=
|
||||
golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
||||
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
|
||||
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
|
||||
golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
|
||||
google.golang.org/api v0.153.0 h1:N1AwGhielyKFaUqH07/ZSIQR3uNPcV7NVw0vj+j4iR4=
|
||||
google.golang.org/api v0.153.0/go.mod h1:3qNJX5eOmhiWYc67jRA/3GsDw97UFb5ivv7Y2PrriAY=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 h1:wpZ8pe2x1Q3f2KyT5f8oP/fa9rHAKgFPr/HZdNuS+PQ=
|
||||
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy1+IPwWHZUzoD0IccYZIrXILAQpc+Qy9CMhY=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 h1:JpwMPBpFN3uKhdaekDpiNlImDdkUAyiJ6ez/uxGaUSo=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f h1:ultW7fxlIvee4HYrtnaRPon9HpEgFk5zYpmfMgtKB5I=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f/go.mod h1:L9KNLi232K1/xB6f7AlSX692koaRnKaWSR0stBki0Yc=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
|
||||
google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
|
||||
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
@ -392,6 +245,4 @@ gorm.io/driver/mysql v1.5.2/go.mod h1:pQLhh1Ut/WUAySdTHwBpBv6+JKcj+ua4ZFx1QQTBzb
|
||||
gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
|
||||
gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls=
|
||||
gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
|
||||
@ -31,9 +31,9 @@ type PasswordPromptFunc func(prompt string) (string, error)
|
||||
|
||||
// RAGFlowClient handles API interactions with the RAGFlow server
|
||||
type RAGFlowClient struct {
|
||||
HTTPClient *HTTPClient
|
||||
ServerType string // "admin" or "user"
|
||||
PasswordPrompt PasswordPromptFunc // Function for password input
|
||||
HTTPClient *HTTPClient
|
||||
ServerType string // "admin" or "user"
|
||||
PasswordPrompt PasswordPromptFunc // Function for password input
|
||||
}
|
||||
|
||||
// NewRAGFlowClient creates a new RAGFlow client
|
||||
@ -489,6 +489,28 @@ func (c *RAGFlowClient) getDatasetID(datasetName string) (string, error) {
|
||||
return "", fmt.Errorf("dataset '%s' not found", datasetName)
|
||||
}
|
||||
|
||||
// formatEmptyArray converts empty arrays to "[]" string
|
||||
func formatEmptyArray(v interface{}) string {
|
||||
if v == nil {
|
||||
return "[]"
|
||||
}
|
||||
switch val := v.(type) {
|
||||
case []interface{}:
|
||||
if len(val) == 0 {
|
||||
return "[]"
|
||||
}
|
||||
case []string:
|
||||
if len(val) == 0 {
|
||||
return "[]"
|
||||
}
|
||||
case []int:
|
||||
if len(val) == 0 {
|
||||
return "[]"
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("%v", v)
|
||||
}
|
||||
|
||||
// SearchOnDatasets searches for chunks in specified datasets
|
||||
// Returns (result_map, error) - result_map is non-nil for benchmark mode
|
||||
func (c *RAGFlowClient) SearchOnDatasets(cmd *Command) (map[string]interface{}, error) {
|
||||
@ -582,6 +604,22 @@ func (c *RAGFlowClient) SearchOnDatasets(cmd *Command) (map[string]interface{},
|
||||
"term_similarity": chunkMap["term_similarity"],
|
||||
"vector_similarity": chunkMap["vector_similarity"],
|
||||
}
|
||||
// Add optional fields that may be empty arrays
|
||||
if v, ok := chunkMap["doc_type_kwd"]; ok {
|
||||
row["doc_type_kwd"] = formatEmptyArray(v)
|
||||
}
|
||||
if v, ok := chunkMap["important_kwd"]; ok {
|
||||
row["important_kwd"] = formatEmptyArray(v)
|
||||
}
|
||||
if v, ok := chunkMap["mom_id"]; ok {
|
||||
row["mom_id"] = formatEmptyArray(v)
|
||||
}
|
||||
if v, ok := chunkMap["positions"]; ok {
|
||||
row["positions"] = formatEmptyArray(v)
|
||||
}
|
||||
if v, ok := chunkMap["content_ltks"]; ok {
|
||||
row["content_ltks"] = v
|
||||
}
|
||||
tableData = append(tableData, row)
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,24 +20,66 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"ragflow/internal/server"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
infinity "github.com/infiniflow/infinity-go-sdk"
|
||||
)
|
||||
|
||||
// Engine Infinity engine implementation
|
||||
// Note: Infinity Go SDK is not yet available. This is a placeholder implementation.
|
||||
// infinityClient Infinity SDK client wrapper
|
||||
type infinityClient struct {
|
||||
conn *infinity.InfinityConnection
|
||||
dbName string
|
||||
}
|
||||
|
||||
// NewInfinityClient creates a new Infinity client using the SDK
|
||||
func NewInfinityClient(cfg *server.InfinityConfig) (*infinityClient, error) {
|
||||
// Parse URI like "localhost:23817" to get IP and port
|
||||
host := "127.0.0.1"
|
||||
port := 23817
|
||||
|
||||
if cfg.URI != "" {
|
||||
parts := strings.Split(cfg.URI, ":")
|
||||
if len(parts) == 2 {
|
||||
host = parts[0]
|
||||
if p, err := strconv.Atoi(parts[1]); err == nil {
|
||||
port = p
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
conn, err := infinity.Connect(infinity.NetworkAddress{IP: host, Port: port})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to connect to Infinity: %w", err)
|
||||
}
|
||||
|
||||
return &infinityClient{
|
||||
conn: conn,
|
||||
dbName: cfg.DBName,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Engine Infinity engine implementation using Go SDK
|
||||
type infinityEngine struct {
|
||||
config *server.InfinityConfig
|
||||
client *infinityClient
|
||||
}
|
||||
|
||||
// NewEngine creates an Infinity engine
|
||||
// Note: This is a placeholder implementation waiting for official Infinity Go SDK
|
||||
func NewEngine(cfg interface{}) (*infinityEngine, error) {
|
||||
infConfig, ok := cfg.(*server.InfinityConfig)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid infinity config type, expected *config.InfinityConfig")
|
||||
}
|
||||
|
||||
client, err := NewInfinityClient(infConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
engine := &infinityEngine{
|
||||
config: infConfig,
|
||||
client: client,
|
||||
}
|
||||
|
||||
return engine, nil
|
||||
@ -48,12 +90,22 @@ func (e *infinityEngine) Type() string {
|
||||
return "infinity"
|
||||
}
|
||||
|
||||
// Ping health check
|
||||
// Ping checks if Infinity is accessible
|
||||
func (e *infinityEngine) Ping(ctx context.Context) error {
|
||||
return fmt.Errorf("infinity engine not implemented: waiting for official Go SDK")
|
||||
}
|
||||
|
||||
// Close closes the connection
|
||||
func (e *infinityEngine) Close() error {
|
||||
if e.client == nil || e.client.conn == nil {
|
||||
return fmt.Errorf("Infinity client not initialized")
|
||||
}
|
||||
if !e.client.conn.IsConnected() {
|
||||
return fmt.Errorf("Infinity not connected")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close closes the Infinity connection
|
||||
func (e *infinityEngine) Close() error {
|
||||
if e.client != nil && e.client.conn != nil {
|
||||
_, err := e.client.conn.Disconnect()
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -19,12 +19,138 @@ package infinity
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"ragflow/internal/engine/types"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"ragflow/internal/engine/types"
|
||||
infinity "github.com/infiniflow/infinity-go-sdk"
|
||||
)
|
||||
|
||||
const (
|
||||
PAGERANK_FLD = "pagerank_fea"
|
||||
TAG_FLD = "tag_feas"
|
||||
)
|
||||
|
||||
type SortType int
|
||||
|
||||
const (
|
||||
SortAsc SortType = 0
|
||||
SortDesc SortType = 1
|
||||
)
|
||||
|
||||
type OrderByExpr struct {
|
||||
Fields []OrderByField
|
||||
}
|
||||
|
||||
type OrderByField struct {
|
||||
Field string
|
||||
Type SortType
|
||||
}
|
||||
|
||||
// fieldKeyword checks if field is a keyword field
|
||||
func fieldKeyword(fieldName string) bool {
|
||||
// Treat "*_kwd" tag-like columns as keyword lists except knowledge_graph_kwd
|
||||
if fieldName == "source_id" {
|
||||
return true
|
||||
}
|
||||
if strings.HasSuffix(fieldName, "_kwd") &&
|
||||
fieldName != "knowledge_graph_kwd" &&
|
||||
fieldName != "docnm_kwd" &&
|
||||
fieldName != "important_kwd" &&
|
||||
fieldName != "question_kwd" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// equivalentConditionToStr converts condition dict to filter string
|
||||
func equivalentConditionToStr(condition map[string]interface{}, tableColumns map[string]struct {
|
||||
Type string
|
||||
Default interface{}
|
||||
}) string {
|
||||
if len(condition) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
var conditions []string
|
||||
|
||||
for k, v := range condition {
|
||||
if !strings.HasPrefix(k, "_") {
|
||||
continue
|
||||
}
|
||||
if v == nil || v == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
// Handle keyword fields with filter_fulltext
|
||||
if fieldKeyword(k) {
|
||||
if listVal, isList := v.([]interface{}); isList {
|
||||
var orConds []string
|
||||
for _, item := range listVal {
|
||||
if strItem, ok := item.(string); ok {
|
||||
strItem = strings.ReplaceAll(strItem, "'", "''")
|
||||
orConds = append(orConds, fmt.Sprintf("filter_fulltext('%s', '%s')", convertMatchingField(k), strItem))
|
||||
}
|
||||
}
|
||||
if len(orConds) > 0 {
|
||||
conditions = append(conditions, "("+strings.Join(orConds, " OR ")+")")
|
||||
}
|
||||
} else if strVal, ok := v.(string); ok {
|
||||
strVal = strings.ReplaceAll(strVal, "'", "''")
|
||||
conditions = append(conditions, fmt.Sprintf("filter_fulltext('%s', '%s')", convertMatchingField(k), strVal))
|
||||
}
|
||||
} else if listVal, isList := v.([]interface{}); isList {
|
||||
// Handle IN conditions
|
||||
var inVals []string
|
||||
for _, item := range listVal {
|
||||
if strItem, ok := item.(string); ok {
|
||||
strItem = strings.ReplaceAll(strItem, "'", "''")
|
||||
inVals = append(inVals, fmt.Sprintf("'%s'", strItem))
|
||||
} else {
|
||||
inVals = append(inVals, fmt.Sprintf("%v", item))
|
||||
}
|
||||
}
|
||||
if len(inVals) > 0 {
|
||||
conditions = append(conditions, fmt.Sprintf("%s IN (%s)", k, strings.Join(inVals, ", ")))
|
||||
}
|
||||
} else if k == "must_not" {
|
||||
// Handle must_not conditions
|
||||
if mustNotMap, ok := v.(map[string]interface{}); ok {
|
||||
if existsVal, ok := mustNotMap["exists"]; ok {
|
||||
if existsField, ok := existsVal.(string); ok {
|
||||
col, colOk := tableColumns[existsField]
|
||||
if colOk && strings.Contains(strings.ToLower(col.Type), "char") {
|
||||
conditions = append(conditions, fmt.Sprintf(" %s!='' ", existsField))
|
||||
} else {
|
||||
conditions = append(conditions, fmt.Sprintf("%s!=null", existsField))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if strVal, ok := v.(string); ok {
|
||||
strVal = strings.ReplaceAll(strVal, "'", "''")
|
||||
conditions = append(conditions, fmt.Sprintf("%s='%s'", k, strVal))
|
||||
} else if k == "exists" {
|
||||
if existsField, ok := v.(string); ok {
|
||||
col, colOk := tableColumns[existsField]
|
||||
if colOk && strings.Contains(strings.ToLower(col.Type), "char") {
|
||||
conditions = append(conditions, fmt.Sprintf(" %s!='' ", existsField))
|
||||
} else {
|
||||
conditions = append(conditions, fmt.Sprintf("%s!=null", existsField))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
conditions = append(conditions, fmt.Sprintf("%s=%v", k, v))
|
||||
}
|
||||
}
|
||||
|
||||
if len(conditions) == 0 {
|
||||
return ""
|
||||
}
|
||||
return strings.Join(conditions, " AND ")
|
||||
}
|
||||
|
||||
// SearchRequest Infinity search request (legacy, kept for backward compatibility)
|
||||
type SearchRequest struct {
|
||||
TableName string
|
||||
@ -35,6 +161,7 @@ type SearchRequest struct {
|
||||
Offset int
|
||||
Limit int
|
||||
Filter map[string]interface{}
|
||||
OrderBy *OrderByExpr
|
||||
}
|
||||
|
||||
// SearchResponse Infinity search response
|
||||
@ -69,43 +196,175 @@ type FusionExpr struct {
|
||||
FusionParams map[string]interface{}
|
||||
}
|
||||
|
||||
// Search executes search (supports both unified engine.SearchRequest and legacy SearchRequest)
|
||||
// Search executes search (supports unified engine.SearchRequest only)
|
||||
func (e *infinityEngine) Search(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
switch searchReq := req.(type) {
|
||||
case *types.SearchRequest:
|
||||
return e.searchUnified(ctx, searchReq)
|
||||
case *SearchRequest:
|
||||
return e.searchLegacy(ctx, searchReq)
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid search request type: %T", req)
|
||||
}
|
||||
}
|
||||
|
||||
// convertSelectFields converts field names to Infinity format
|
||||
func convertSelectFields(output []string) []string {
|
||||
fieldMapping := map[string]string{
|
||||
"docnm_kwd": "docnm",
|
||||
"title_tks": "docnm",
|
||||
"title_sm_tks": "docnm",
|
||||
"important_kwd": "important_keywords",
|
||||
"important_tks": "important_keywords",
|
||||
"question_kwd": "questions",
|
||||
"question_tks": "questions",
|
||||
"content_with_weight": "content",
|
||||
"content_ltks": "content",
|
||||
"content_sm_ltks": "content",
|
||||
"authors_tks": "authors",
|
||||
"authors_sm_tks": "authors",
|
||||
}
|
||||
|
||||
needEmptyCount := false
|
||||
for i, field := range output {
|
||||
if field == "important_kwd" {
|
||||
needEmptyCount = true
|
||||
}
|
||||
if newField, ok := fieldMapping[field]; ok {
|
||||
output[i] = newField
|
||||
}
|
||||
}
|
||||
|
||||
// Remove duplicates
|
||||
seen := make(map[string]bool)
|
||||
result := []string{}
|
||||
for _, f := range output {
|
||||
if f != "" && !seen[f] {
|
||||
seen[f] = true
|
||||
result = append(result, f)
|
||||
}
|
||||
}
|
||||
|
||||
// Add id and empty count if needed
|
||||
hasID := false
|
||||
for _, f := range result {
|
||||
if f == "id" {
|
||||
hasID = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasID {
|
||||
result = append([]string{"id"}, result...)
|
||||
}
|
||||
|
||||
if needEmptyCount {
|
||||
result = append(result, "important_kwd_empty_count")
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// isChinese checks if a string contains Chinese characters
|
||||
func isChinese(s string) bool {
|
||||
for _, r := range s {
|
||||
if '\u4e00' <= r && r <= '\u9fff' {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// hasSubTokens checks if the text has sub-tokens after fine-grained tokenization
|
||||
// - Returns False if len < 3
|
||||
// - Returns False if text is only ASCII alphanumeric
|
||||
// - Returns True otherwise (meaning there are sub-tokens)
|
||||
func hasSubTokens(s string) bool {
|
||||
if utf8.RuneCountInString(s) < 3 {
|
||||
return false
|
||||
}
|
||||
isASCIIOnly := true
|
||||
for _, r := range s {
|
||||
if r > 127 {
|
||||
isASCIIOnly = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if isASCIIOnly {
|
||||
// Check if it's only alphanumeric and allowed special chars
|
||||
for _, r := range s {
|
||||
if !((r >= '0' && r <= '9') || (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || r == '.' || r == '+' || r == '#' || r == '_' || r == '*' || r == '-') {
|
||||
isASCIIOnly = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if isASCIIOnly {
|
||||
return false
|
||||
}
|
||||
}
|
||||
// Has sub-tokens if it's Chinese and length >= 3
|
||||
return isChinese(s)
|
||||
}
|
||||
|
||||
// formatQuestion formats the question
|
||||
// - If len < 3: returns ((query)^1.0)
|
||||
// - If has sub-tokens: adds fuzzy search ((query OR "query" OR ("query"~2)^0.5)^1.0)
|
||||
// - Otherwise: returns ((query)^1.0)
|
||||
func formatQuestion(question string) string {
|
||||
// Trim whitespace
|
||||
question = strings.TrimSpace(question)
|
||||
fmt.Printf("[DEBUG formatQuestion] input: %q, len: %d, hasSubTokens: %v\n", question, len(question), hasSubTokens(question))
|
||||
|
||||
// If no sub-tokens, use simple format
|
||||
if !hasSubTokens(question) {
|
||||
result := fmt.Sprintf("((%s)^1.0)", question)
|
||||
fmt.Printf("[DEBUG formatQuestion] simple: %s\n", result)
|
||||
return result
|
||||
}
|
||||
|
||||
result := fmt.Sprintf("((%s OR \"%s\" OR (\"%s\"~2)^0.5)^1.0)", question, question, question)
|
||||
fmt.Printf("[DEBUG formatQuestion] fuzzy: %s\n", result)
|
||||
return result
|
||||
}
|
||||
|
||||
// convertMatchingField converts field names for matching
|
||||
func convertMatchingField(fieldWeightStr string) string {
|
||||
// Split on ^ to get field name
|
||||
parts := strings.Split(fieldWeightStr, "^")
|
||||
field := parts[0]
|
||||
|
||||
// Field name conversion
|
||||
fieldMapping := map[string]string{
|
||||
"docnm_kwd": "docnm@ft_docnm_rag_coarse",
|
||||
"title_tks": "docnm@ft_docnm_rag_coarse",
|
||||
"title_sm_tks": "docnm@ft_docnm_rag_fine",
|
||||
"important_kwd": "important_keywords@ft_important_keywords_rag_coarse",
|
||||
"important_tks": "important_keywords@ft_important_keywords_rag_fine",
|
||||
"question_kwd": "questions@ft_questions_rag_coarse",
|
||||
"question_tks": "questions@ft_questions_rag_fine",
|
||||
"content_with_weight": "content@ft_content_rag_coarse",
|
||||
"content_ltks": "content@ft_content_rag_coarse",
|
||||
"content_sm_ltks": "content@ft_content_rag_fine",
|
||||
"authors_tks": "authors@ft_authors_rag_coarse",
|
||||
"authors_sm_tks": "authors@ft_authors_rag_fine",
|
||||
}
|
||||
|
||||
if newField, ok := fieldMapping[field]; ok {
|
||||
parts[0] = newField
|
||||
}
|
||||
|
||||
return strings.Join(parts, "^")
|
||||
}
|
||||
|
||||
// searchUnified handles the unified engine.SearchRequest
|
||||
func (e *infinityEngine) searchUnified(ctx context.Context, req *types.SearchRequest) (*types.SearchResponse, error) {
|
||||
if len(req.IndexNames) == 0 {
|
||||
return nil, fmt.Errorf("index names cannot be empty")
|
||||
}
|
||||
|
||||
// For Infinity, we use the first index name as table name
|
||||
tableName := req.IndexNames[0]
|
||||
|
||||
// Get retrieval parameters with defaults
|
||||
similarityThreshold := req.SimilarityThreshold
|
||||
if similarityThreshold <= 0 {
|
||||
similarityThreshold = 0.1
|
||||
}
|
||||
|
||||
topK := req.TopK
|
||||
if topK <= 0 {
|
||||
topK = 1024
|
||||
}
|
||||
|
||||
vectorSimilarityWeight := req.VectorSimilarityWeight
|
||||
if vectorSimilarityWeight < 0 || vectorSimilarityWeight > 1 {
|
||||
vectorSimilarityWeight = 0.3
|
||||
}
|
||||
|
||||
pageSize := req.Size
|
||||
if pageSize <= 0 {
|
||||
pageSize = 30
|
||||
@ -116,90 +375,546 @@ func (e *infinityEngine) searchUnified(ctx context.Context, req *types.SearchReq
|
||||
offset = 0
|
||||
}
|
||||
|
||||
// Build search request
|
||||
searchReq := &SearchRequest{
|
||||
TableName: tableName,
|
||||
Limit: pageSize,
|
||||
Offset: offset,
|
||||
Filter: buildInfinityFilters(req.KbIDs, req.DocIDs),
|
||||
// Get database
|
||||
db, err := e.client.conn.GetDatabase(e.client.dbName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get database: %w", err)
|
||||
}
|
||||
|
||||
// Add text match (question is always required)
|
||||
searchReq.MatchText = &MatchTextExpr{
|
||||
Fields: []string{"title_tks", "content_ltks"},
|
||||
MatchingText: req.Question,
|
||||
TopN: topK,
|
||||
// Build output columns
|
||||
// Include all fields needed for retrieval test results
|
||||
outputColumns := []string{
|
||||
"id",
|
||||
"doc_id",
|
||||
"kb_id",
|
||||
"content",
|
||||
"content_ltks",
|
||||
"content_with_weight",
|
||||
"title_tks",
|
||||
"docnm_kwd",
|
||||
"img_id",
|
||||
"available_int",
|
||||
"important_kwd",
|
||||
"position_int",
|
||||
"page_num_int",
|
||||
"doc_type_kwd",
|
||||
"mom_id",
|
||||
"question_tks",
|
||||
}
|
||||
outputColumns = convertSelectFields(outputColumns)
|
||||
|
||||
// Determine if text or vector search
|
||||
hasTextMatch := req.Question != ""
|
||||
hasVectorMatch := !req.KeywordOnly && len(req.Vector) > 0
|
||||
|
||||
// Determine score column
|
||||
scoreColumn := ""
|
||||
if hasTextMatch {
|
||||
scoreColumn = "SCORE"
|
||||
} else if hasVectorMatch {
|
||||
scoreColumn = "SIMILARITY"
|
||||
}
|
||||
|
||||
// Add vector match if vector is provided and not keyword-only mode
|
||||
if !req.KeywordOnly && len(req.Vector) > 0 {
|
||||
fieldName := buildInfinityVectorFieldName(req.Vector)
|
||||
searchReq.MatchDense = &MatchDenseExpr{
|
||||
VectorColumnName: fieldName,
|
||||
EmbeddingData: req.Vector,
|
||||
EmbeddingDataType: "float",
|
||||
DistanceType: "cosine",
|
||||
TopN: topK,
|
||||
ExtraOptions: map[string]interface{}{
|
||||
"similarity": similarityThreshold,
|
||||
},
|
||||
}
|
||||
// Infinity uses weighted_sum fusion with weights
|
||||
searchReq.Fusion = &FusionExpr{
|
||||
Method: "weighted_sum",
|
||||
TopN: topK,
|
||||
Weights: []float64{
|
||||
1.0 - vectorSimilarityWeight, // text weight
|
||||
vectorSimilarityWeight, // vector weight
|
||||
},
|
||||
// Add score column if needed
|
||||
if hasTextMatch || hasVectorMatch {
|
||||
if hasTextMatch {
|
||||
outputColumns = append(outputColumns, "score()")
|
||||
} else if hasVectorMatch {
|
||||
outputColumns = append(outputColumns, "similarity()")
|
||||
}
|
||||
// Add pagerank field
|
||||
outputColumns = append(outputColumns, PAGERANK_FLD)
|
||||
}
|
||||
|
||||
// Execute the actual search (would call Infinity SDK here)
|
||||
// For now, return not implemented
|
||||
return nil, fmt.Errorf("infinity search unified not implemented: waiting for official Go SDK")
|
||||
}
|
||||
// Remove duplicates
|
||||
outputColumns = convertSelectFields(outputColumns)
|
||||
|
||||
// searchLegacy handles the legacy infinity.SearchRequest (backward compatibility)
|
||||
func (e *infinityEngine) searchLegacy(ctx context.Context, req *SearchRequest) (*SearchResponse, error) {
|
||||
// This would contain the actual Infinity search implementation
|
||||
return nil, fmt.Errorf("infinity search legacy not implemented: waiting for official Go SDK")
|
||||
}
|
||||
|
||||
// buildInfinityFilters builds filter conditions for Infinity
|
||||
func buildInfinityFilters(kbIDs []string, docIDs []string) map[string]interface{} {
|
||||
filters := make(map[string]interface{})
|
||||
|
||||
// kb_id filter
|
||||
if len(kbIDs) > 0 {
|
||||
if len(kbIDs) == 1 {
|
||||
filters["kb_id"] = kbIDs[0]
|
||||
// Build filter string
|
||||
var filterParts []string
|
||||
if len(req.DocIDs) > 0 {
|
||||
if len(req.DocIDs) == 1 {
|
||||
filterParts = append(filterParts, fmt.Sprintf("doc_id = '%s'", req.DocIDs[0]))
|
||||
} else {
|
||||
filters["kb_id"] = kbIDs
|
||||
docIDs := strings.Join(req.DocIDs, "', '")
|
||||
filterParts = append(filterParts, fmt.Sprintf("doc_id IN ('%s')", docIDs))
|
||||
}
|
||||
}
|
||||
// Default filter for available chunks
|
||||
filterParts = append(filterParts, "available_int=1")
|
||||
|
||||
filterStr := strings.Join(filterParts, " AND ")
|
||||
|
||||
// Build order_by
|
||||
var orderBy *OrderByExpr
|
||||
if req.OrderBy != "" {
|
||||
orderBy = &OrderByExpr{Fields: []OrderByField{}}
|
||||
// Parse order_by field and direction
|
||||
fields := strings.Split(req.OrderBy, ",")
|
||||
for _, field := range fields {
|
||||
field = strings.TrimSpace(field)
|
||||
if strings.HasSuffix(field, " desc") || strings.HasSuffix(field, " DESC") {
|
||||
fieldName := strings.TrimSuffix(field, " desc")
|
||||
fieldName = strings.TrimSuffix(fieldName, " DESC")
|
||||
orderBy.Fields = append(orderBy.Fields, OrderByField{Field: fieldName, Type: SortDesc})
|
||||
} else {
|
||||
orderBy.Fields = append(orderBy.Fields, OrderByField{Field: field, Type: SortAsc})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// doc_id filter
|
||||
if len(docIDs) > 0 {
|
||||
if len(docIDs) == 1 {
|
||||
filters["doc_id"] = docIDs[0]
|
||||
// rank_feature support
|
||||
var rankFeature map[string]float64
|
||||
if req.RankFeature != nil {
|
||||
rankFeature = req.RankFeature
|
||||
}
|
||||
|
||||
// Results from all tables
|
||||
var allResults []map[string]interface{}
|
||||
totalHits := int64(0)
|
||||
|
||||
// Search across all tables
|
||||
for _, indexName := range req.IndexNames {
|
||||
// Determine table names to search
|
||||
var tableNames []string
|
||||
if strings.HasPrefix(indexName, "ragflow_doc_meta_") {
|
||||
tableNames = []string{indexName}
|
||||
} else {
|
||||
filters["doc_id"] = docIDs
|
||||
// For each KB ID, create a table name
|
||||
kbIDs := req.KbIDs
|
||||
if len(kbIDs) == 0 {
|
||||
// If no KB IDs, use the index name directly
|
||||
kbIDs = []string{""}
|
||||
}
|
||||
for _, kbID := range kbIDs {
|
||||
if kbID == "" {
|
||||
tableNames = append(tableNames, indexName)
|
||||
} else {
|
||||
tableNames = append(tableNames, fmt.Sprintf("%s_%s", indexName, kbID))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Search each table
|
||||
// 1. First try with min_match=0.3 (30%)
|
||||
// 2. If no results and has doc_id filter: search without match
|
||||
// 3. If no results and no doc_id filter: retry with min_match=0.1 (10%) and lower similarity
|
||||
minMatch := 0.3
|
||||
hasDocIDFilter := len(req.DocIDs) > 0
|
||||
|
||||
for _, tableName := range tableNames {
|
||||
fmt.Printf("[DEBUG] Searching table: %s\n", tableName)
|
||||
// Try to get table
|
||||
_, err := db.GetTable(tableName)
|
||||
if err != nil {
|
||||
// Table doesn't exist, skip
|
||||
continue
|
||||
}
|
||||
|
||||
// Build query for this table
|
||||
result, err := e.executeTableSearch(db, tableName, outputColumns, req.Question, req.Vector, filterStr, topK, pageSize, offset, orderBy, rankFeature, req.SimilarityThreshold, minMatch)
|
||||
if err != nil {
|
||||
// Skip this table on error
|
||||
continue
|
||||
}
|
||||
|
||||
allResults = append(allResults, result.Chunks...)
|
||||
totalHits += result.Total
|
||||
}
|
||||
|
||||
// If no results, try fallback strategies
|
||||
if totalHits == 0 && (hasTextMatch || hasVectorMatch) {
|
||||
fmt.Printf("[DEBUG] No results, trying fallback strategies\n")
|
||||
allResults = nil
|
||||
totalHits = 0
|
||||
|
||||
if hasDocIDFilter {
|
||||
// If has doc_id filter, search without match
|
||||
fmt.Printf("[DEBUG] Retry with no match (has doc_id filter)\n")
|
||||
for _, tableName := range tableNames {
|
||||
_, err := db.GetTable(tableName)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
// Search without match - pass empty question
|
||||
result, err := e.executeTableSearch(db, tableName, outputColumns, "", req.Vector, filterStr, topK, pageSize, offset, orderBy, rankFeature, req.SimilarityThreshold, 0.0)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
allResults = append(allResults, result.Chunks...)
|
||||
totalHits += result.Total
|
||||
}
|
||||
} else {
|
||||
// Retry with lower min_match and similarity
|
||||
fmt.Printf("[DEBUG] Retry with min_match=0.1, similarity=0.17\n")
|
||||
lowerThreshold := 0.17
|
||||
for _, tableName := range tableNames {
|
||||
_, err := db.GetTable(tableName)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
result, err := e.executeTableSearch(db, tableName, outputColumns, req.Question, req.Vector, filterStr, topK, pageSize, offset, orderBy, rankFeature, lowerThreshold, 0.1)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
allResults = append(allResults, result.Chunks...)
|
||||
totalHits += result.Total
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// available_int filter (default to 1 for available chunks)
|
||||
filters["available_int"] = 1
|
||||
if hasTextMatch || hasVectorMatch {
|
||||
allResults = calculateScores(allResults, scoreColumn, PAGERANK_FLD)
|
||||
}
|
||||
|
||||
return filters
|
||||
if hasTextMatch || hasVectorMatch {
|
||||
allResults = sortByScore(allResults, len(allResults))
|
||||
}
|
||||
|
||||
// Apply threshold filter to combined results
|
||||
fmt.Printf("[DEBUG] Threshold check: SimilarityThreshold=%f, hasVectorMatch=%v, hasTextMatch=%v\n", req.SimilarityThreshold, hasVectorMatch, hasTextMatch)
|
||||
if req.SimilarityThreshold > 0 && hasVectorMatch {
|
||||
var filteredResults []map[string]interface{}
|
||||
for _, chunk := range allResults {
|
||||
score := getScore(chunk)
|
||||
chunkID := ""
|
||||
if id, ok := chunk["id"]; ok {
|
||||
chunkID = fmt.Sprintf("%v", id)
|
||||
}
|
||||
fmt.Printf("[DEBUG] Threshold filter: id=%s, score=%f, threshold=%f, pass=%v\n", chunkID, score, req.SimilarityThreshold, score >= req.SimilarityThreshold)
|
||||
if score >= req.SimilarityThreshold {
|
||||
filteredResults = append(filteredResults, chunk)
|
||||
}
|
||||
}
|
||||
fmt.Printf("[DEBUG] After threshold filter (combined): %d -> %d chunks\n", len(allResults), len(filteredResults))
|
||||
allResults = filteredResults
|
||||
}
|
||||
|
||||
// Limit to pageSize
|
||||
if len(allResults) > pageSize {
|
||||
allResults = allResults[:pageSize]
|
||||
}
|
||||
|
||||
return &types.SearchResponse{
|
||||
Chunks: allResults,
|
||||
Total: totalHits,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// buildInfinityVectorFieldName builds vector field name based on dimension
|
||||
func buildInfinityVectorFieldName(vector []float64) string {
|
||||
dimension := len(vector)
|
||||
var fieldBuilder strings.Builder
|
||||
fieldBuilder.WriteString("q_")
|
||||
fieldBuilder.WriteString(strconv.Itoa(dimension))
|
||||
fieldBuilder.WriteString("_vec")
|
||||
return fieldBuilder.String()
|
||||
// calculateScores calculates _score = score_column + pagerank
|
||||
func calculateScores(chunks []map[string]interface{}, scoreColumn, pagerankField string) []map[string]interface{} {
|
||||
fmt.Printf("[DEBUG] calculateScores: scoreColumn=%s, pagerankField=%s\n", scoreColumn, pagerankField)
|
||||
for i := range chunks {
|
||||
score := 0.0
|
||||
if scoreVal, ok := chunks[i][scoreColumn]; ok {
|
||||
if f, ok := toFloat64(scoreVal); ok {
|
||||
score += f
|
||||
fmt.Printf("[DEBUG] chunk[%d]: %s=%f\n", i, scoreColumn, f)
|
||||
}
|
||||
}
|
||||
if pagerankVal, ok := chunks[i][pagerankField]; ok {
|
||||
if f, ok := toFloat64(pagerankVal); ok {
|
||||
score += f
|
||||
}
|
||||
}
|
||||
chunks[i]["_score"] = score
|
||||
fmt.Printf("[DEBUG] chunk[%d]: _score=%f\n", i, score)
|
||||
}
|
||||
return chunks
|
||||
}
|
||||
|
||||
// sortByScore sorts by _score descending and limits
|
||||
func sortByScore(chunks []map[string]interface{}, limit int) []map[string]interface{} {
|
||||
if len(chunks) == 0 {
|
||||
return chunks
|
||||
}
|
||||
|
||||
// Sort by _score descending
|
||||
for i := 0; i < len(chunks)-1; i++ {
|
||||
for j := i + 1; j < len(chunks); j++ {
|
||||
scoreI := getScore(chunks[i])
|
||||
scoreJ := getScore(chunks[j])
|
||||
if scoreI < scoreJ {
|
||||
chunks[i], chunks[j] = chunks[j], chunks[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Limit
|
||||
if len(chunks) > limit && limit > 0 {
|
||||
chunks = chunks[:limit]
|
||||
}
|
||||
|
||||
return chunks
|
||||
}
|
||||
|
||||
func getScore(chunk map[string]interface{}) float64 {
|
||||
// Check _score first
|
||||
if score, ok := chunk["_score"].(float64); ok {
|
||||
return score
|
||||
}
|
||||
if score, ok := chunk["_score"].(int); ok {
|
||||
return float64(score)
|
||||
}
|
||||
if score, ok := chunk["_score"].(int64); ok {
|
||||
return float64(score)
|
||||
}
|
||||
// Fallback to SCORE (for fusion) or SIMILARITY (for vector-only)
|
||||
if score, ok := chunk["SCORE"].(float64); ok {
|
||||
return score
|
||||
}
|
||||
if score, ok := chunk["SIMILARITY"].(float64); ok {
|
||||
return score
|
||||
}
|
||||
return 0.0
|
||||
}
|
||||
|
||||
func toFloat64(val interface{}) (float64, bool) {
|
||||
switch v := val.(type) {
|
||||
case float64:
|
||||
return v, true
|
||||
case float32:
|
||||
return float64(v), true
|
||||
case int:
|
||||
return float64(v), true
|
||||
case int64:
|
||||
return float64(v), true
|
||||
case string:
|
||||
f, err := strconv.ParseFloat(v, 64)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
return f, true
|
||||
default:
|
||||
return 0, false
|
||||
}
|
||||
}
|
||||
|
||||
// executeTableSearch executes search on a single table
|
||||
func (e *infinityEngine) executeTableSearch(db *infinity.Database, tableName string, outputColumns []string, question string, vector []float64, filterStr string, topK, pageSize, offset int, orderBy *OrderByExpr, rankFeature map[string]float64, similarityThreshold float64, minMatch float64) (*types.SearchResponse, error) {
|
||||
// Debug logging
|
||||
fmt.Printf("[DEBUG] executeTableSearch: question=%s, topK=%d, pageSize=%d, similarityThreshold=%f, rankFeature=%v\n", question, topK, pageSize, similarityThreshold, rankFeature)
|
||||
|
||||
// Get table
|
||||
table, err := db.GetTable(tableName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Build query using Table's chainable methods
|
||||
hasTextMatch := question != ""
|
||||
hasVectorMatch := len(vector) > 0
|
||||
|
||||
table = table.Output(outputColumns)
|
||||
|
||||
// Define text fields
|
||||
textFields := []string{
|
||||
"title_tks^10",
|
||||
"title_sm_tks^5",
|
||||
"important_kwd^30",
|
||||
"important_tks^20",
|
||||
"question_tks^20",
|
||||
"content_ltks^2",
|
||||
"content_sm_ltks",
|
||||
}
|
||||
|
||||
// Convert field names for Infinity
|
||||
var convertedFields []string
|
||||
for _, f := range textFields {
|
||||
cf := convertMatchingField(f)
|
||||
convertedFields = append(convertedFields, cf)
|
||||
}
|
||||
fields := strings.Join(convertedFields, ",")
|
||||
|
||||
// Format question
|
||||
formattedQuestion := formatQuestion(question)
|
||||
|
||||
// Compute full filter with filter_fulltext for MatchDense extra_options
|
||||
var fullFilterWithFulltext string
|
||||
if filterStr != "" && fields != "" {
|
||||
fullFilterWithFulltext = fmt.Sprintf("(%s) AND FILTER_FULLTEXT('%s', '%s')", filterStr, fields, formattedQuestion)
|
||||
}
|
||||
|
||||
// Add text match if question is provided
|
||||
if hasTextMatch {
|
||||
extraOptions := map[string]string{
|
||||
"topn": fmt.Sprintf("%d", topK),
|
||||
"minimum_should_match": fmt.Sprintf("%d%%", int(minMatch*100)),
|
||||
}
|
||||
|
||||
// Add rank_features support
|
||||
if rankFeature != nil {
|
||||
var rankFeaturesList []string
|
||||
for featureName, weight := range rankFeature {
|
||||
rankFeaturesList = append(rankFeaturesList, fmt.Sprintf("%s^%s^%f", TAG_FLD, featureName, weight))
|
||||
}
|
||||
if len(rankFeaturesList) > 0 {
|
||||
extraOptions["rank_features"] = strings.Join(rankFeaturesList, ",")
|
||||
}
|
||||
}
|
||||
|
||||
table = table.MatchText(fields, formattedQuestion, topK, extraOptions)
|
||||
fmt.Printf("[DEBUG] MatchTextExpr: fields=%s, matching_text=%s, topn=%d, extra_options=%v\n", fields, formattedQuestion, topK, extraOptions)
|
||||
}
|
||||
|
||||
// Add vector match if provided
|
||||
if hasVectorMatch {
|
||||
vectorSize := len(vector)
|
||||
fieldName := fmt.Sprintf("q_%d_vec", vectorSize)
|
||||
threshold := similarityThreshold
|
||||
if threshold <= 0 {
|
||||
threshold = 0.1 // default
|
||||
}
|
||||
extraOptions := map[string]string{
|
||||
// Add threshold
|
||||
"threshold": fmt.Sprintf("%f", threshold),
|
||||
}
|
||||
|
||||
// Add filter with filter_fulltext, add to MatchDense extra_options
|
||||
// This is the full filter that includes both available_int=1 AND filter_fulltext
|
||||
if fullFilterWithFulltext != "" {
|
||||
extraOptions["filter"] = fullFilterWithFulltext
|
||||
fmt.Printf("[DEBUG] filterStr=%s, fullFilterWithFulltext=%s\n", filterStr, fullFilterWithFulltext)
|
||||
}
|
||||
|
||||
fmt.Printf("[DEBUG] MatchDenseExpr: field=%s, topn=%d, extra_options=%v\n", fieldName, topK, extraOptions)
|
||||
|
||||
table = table.MatchDense(fieldName, vector, "float", "cosine", topK, extraOptions)
|
||||
}
|
||||
|
||||
// Add fusion (for text+vector combination)
|
||||
if hasTextMatch && hasVectorMatch {
|
||||
fusionParams := map[string]interface{}{
|
||||
"normalize": "atan",
|
||||
"weights": "0.05,0.95",
|
||||
}
|
||||
fmt.Printf("[DEBUG] FusionExpr: method=weighted_sum, topn=%d, fusion_params=%v\n", topK, fusionParams)
|
||||
fmt.Printf("[DEBUG] Before Fusion - table has MatchText=%v, MatchDense=%v\n", hasTextMatch, hasVectorMatch)
|
||||
table = table.Fusion("weighted_sum", topK, fusionParams)
|
||||
}
|
||||
|
||||
// Add order_by if provided
|
||||
if orderBy != nil && len(orderBy.Fields) > 0 {
|
||||
var sortFields [][2]interface{}
|
||||
for _, field := range orderBy.Fields {
|
||||
sortType := infinity.SortTypeAsc
|
||||
if field.Type == SortDesc {
|
||||
sortType = infinity.SortTypeDesc
|
||||
}
|
||||
sortFields = append(sortFields, [2]interface{}{field.Field, sortType})
|
||||
}
|
||||
table = table.Sort(sortFields)
|
||||
}
|
||||
|
||||
// Set limit and offset
|
||||
// Use topK to get more results from Infinity, then filter/sort in Go
|
||||
table = table.Limit(topK)
|
||||
if offset > 0 {
|
||||
table = table.Offset(offset)
|
||||
}
|
||||
|
||||
// Execute query - get the raw query and execute via SDK
|
||||
result, err := e.executeQuery(table)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Debug logging - show returned chunks
|
||||
scoreColumn := "SIMILARITY"
|
||||
if hasTextMatch {
|
||||
scoreColumn = "SCORE"
|
||||
}
|
||||
fmt.Printf("[DEBUG] executeTableSearch returned %d chunks\n", len(result.Chunks))
|
||||
|
||||
result.Chunks = calculateScores(result.Chunks, scoreColumn, PAGERANK_FLD)
|
||||
|
||||
// Debug after calculateScores
|
||||
for i, chunk := range result.Chunks {
|
||||
chunkID := ""
|
||||
if id, ok := chunk["id"]; ok {
|
||||
chunkID = fmt.Sprintf("%v", id)
|
||||
}
|
||||
score := getScore(chunk)
|
||||
fmt.Printf("[DEBUG] chunk[%d]: id=%s, _score=%f\n", i, chunkID, score)
|
||||
}
|
||||
|
||||
// Sort by score
|
||||
result.Chunks = sortByScore(result.Chunks, len(result.Chunks))
|
||||
|
||||
if len(result.Chunks) > pageSize {
|
||||
result.Chunks = result.Chunks[:pageSize]
|
||||
}
|
||||
result.Total = int64(len(result.Chunks))
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// executeQuery executes the query and returns results
|
||||
func (e *infinityEngine) executeQuery(table *infinity.Table) (*types.SearchResponse, error) {
|
||||
// Use ToResult() to execute query
|
||||
result, err := table.ToResult()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Infinity query failed: %w", err)
|
||||
}
|
||||
|
||||
// Debug: print raw result info
|
||||
// fmt.Printf("[DEBUG] Infinity raw result: %+v\n", result)
|
||||
|
||||
// Convert result to SearchResponse format
|
||||
// The SDK returns QueryResult with Data as map[string][]interface{}
|
||||
qr, ok := result.(*infinity.QueryResult)
|
||||
if !ok {
|
||||
return &types.SearchResponse{
|
||||
Chunks: []map[string]interface{}{},
|
||||
Total: 0,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Convert to chunks format
|
||||
chunks := make([]map[string]interface{}, 0)
|
||||
for colName, colData := range qr.Data {
|
||||
for i, val := range colData {
|
||||
// Ensure we have a row for this index
|
||||
for len(chunks) <= i {
|
||||
chunks = append(chunks, make(map[string]interface{}))
|
||||
}
|
||||
chunks[i][colName] = val
|
||||
}
|
||||
}
|
||||
|
||||
// Post-process: convert nil/empty values to empty slices for array-like fields
|
||||
arrayFields := map[string]bool{
|
||||
"doc_type_kwd": true,
|
||||
"important_kwd": true,
|
||||
"important_tks": true,
|
||||
"question_tks": true,
|
||||
"authors_tks": true,
|
||||
"authors_sm_tks": true,
|
||||
"title_tks": true,
|
||||
"title_sm_tks": true,
|
||||
"content_ltks": true,
|
||||
"content_sm_ltks": true,
|
||||
}
|
||||
for i := range chunks {
|
||||
for colName := range arrayFields {
|
||||
if val, ok := chunks[i][colName]; !ok || val == nil || val == "" {
|
||||
chunks[i][colName] = []interface{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &types.SearchResponse{
|
||||
Chunks: chunks,
|
||||
Total: int64(len(chunks)),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// contains checks if slice contains string
|
||||
func contains(slice []string, item string) bool {
|
||||
for _, s := range slice {
|
||||
if s == item {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@ -43,6 +43,10 @@ type SearchRequest struct {
|
||||
SimilarityThreshold float64 // Minimum similarity score (default: 0.1)
|
||||
VectorSimilarityWeight float64 // Weight for vector vs keyword (default: 0.3)
|
||||
|
||||
// Sorting and ranking
|
||||
OrderBy string // Order by field (e.g., "field1 desc, field2 asc")
|
||||
RankFeature map[string]float64 // Rank features for learning to rank
|
||||
|
||||
// Engine-specific options (optional, for advanced use)
|
||||
Options map[string]interface{}
|
||||
}
|
||||
|
||||
@ -414,7 +414,11 @@ func Init(configPath string) error {
|
||||
|
||||
// Map doc_engine section to DocEngineConfig
|
||||
if globalConfig != nil && globalConfig.DocEngine.Type == "" {
|
||||
// Try to map from doc_engine section
|
||||
// Use DOC_ENGINE env var if set
|
||||
if docEngine != "" {
|
||||
globalConfig.DocEngine.Type = EngineType(docEngine)
|
||||
}
|
||||
// Try to map from doc_engine section (overrides env var if present)
|
||||
if v.IsSet("doc_engine") {
|
||||
docEngineConfig := v.Sub("doc_engine")
|
||||
if docEngineConfig != nil {
|
||||
|
||||
@ -20,6 +20,8 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"ragflow/internal/server"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
@ -348,10 +350,10 @@ func getSimilarityThreshold(threshold *float64) float64 {
|
||||
}
|
||||
|
||||
func getVectorSimilarityWeight(weight *float64) float64 {
|
||||
//if weight != nil && *weight >= 0 && *weight <= 1 {
|
||||
// return *weight
|
||||
//}
|
||||
return 0.95
|
||||
if weight != nil && *weight >= 0 && *weight <= 1 {
|
||||
return *weight
|
||||
}
|
||||
return 0.3
|
||||
}
|
||||
|
||||
func buildIndexNames(tenantIDs []string) []string {
|
||||
@ -424,19 +426,28 @@ func buildRetrievalTestResults(filteredChunks []map[string]interface{}) []map[st
|
||||
result := make(map[string]interface{})
|
||||
|
||||
// Key mappings
|
||||
if v, ok := chunk["_id"]; ok {
|
||||
if v, ok := chunk["id"]; ok {
|
||||
result["chunk_id"] = v
|
||||
} else if v, ok := chunk["_id"]; ok {
|
||||
result["chunk_id"] = v
|
||||
}
|
||||
if v, ok := chunk["content_ltks"]; ok {
|
||||
if v, ok := chunk["content"]; ok {
|
||||
result["content_ltks"] = v
|
||||
}
|
||||
if v, ok := chunk["content_with_weight"]; ok {
|
||||
result["content_with_weight"] = v
|
||||
} else {
|
||||
if v, ok := chunk["content_ltks"]; ok {
|
||||
result["content_ltks"] = v
|
||||
}
|
||||
if v, ok := chunk["content_with_weight"]; ok {
|
||||
result["content_with_weight"] = v
|
||||
}
|
||||
}
|
||||
if v, ok := chunk["doc_id"]; ok {
|
||||
result["doc_id"] = v
|
||||
}
|
||||
if v, ok := chunk["docnm_kwd"]; ok {
|
||||
if v, ok := chunk["docnm"]; ok {
|
||||
result["docnm_kwd"] = v
|
||||
} else if v, ok := chunk["docnm_kwd"]; ok {
|
||||
result["docnm_kwd"] = v
|
||||
}
|
||||
if v, ok := chunk["img_id"]; ok {
|
||||
@ -446,7 +457,22 @@ func buildRetrievalTestResults(filteredChunks []map[string]interface{}) []map[st
|
||||
result["kb_id"] = v
|
||||
}
|
||||
if v, ok := chunk["position_int"]; ok {
|
||||
result["positions"] = v
|
||||
if strVal, ok := v.(string); ok && strVal != "" {
|
||||
result["positions"] = convertPositionInt(strVal)
|
||||
} else {
|
||||
result["positions"] = []interface{}{}
|
||||
}
|
||||
}
|
||||
if v, ok := chunk["doc_type_kwd"]; ok {
|
||||
result["doc_type_kwd"] = v
|
||||
}
|
||||
if v, ok := chunk["mom_id"]; ok {
|
||||
result["mom_id"] = v
|
||||
}
|
||||
if v, ok := chunk["important_kwd"]; ok {
|
||||
result["important_kwd"] = v
|
||||
} else if v, ok := chunk["important_keywords"]; ok {
|
||||
result["important_kwd"] = v
|
||||
}
|
||||
if v, ok := chunk["similarity"]; ok {
|
||||
result["similarity"] = v
|
||||
@ -463,3 +489,43 @@ func buildRetrievalTestResults(filteredChunks []map[string]interface{}) []map[st
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
// convertPositionInt converts hex string format "00000001_0000005e_..." to array [[1, 94, ...], ...]
|
||||
func convertPositionInt(hexStr string) []interface{} {
|
||||
if hexStr == "" {
|
||||
return []interface{}{}
|
||||
}
|
||||
|
||||
parts := strings.Split(hexStr, "_")
|
||||
var intVals []int
|
||||
for _, part := range parts {
|
||||
if part == "" {
|
||||
continue
|
||||
}
|
||||
// Parse hex string (without 0x prefix)
|
||||
val, err := strconv.ParseInt(part, 16, 64)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
intVals = append(intVals, int(val))
|
||||
}
|
||||
|
||||
// Group by 5 elements
|
||||
var result []interface{}
|
||||
for i := 0; i < len(intVals); i += 5 {
|
||||
end := i + 5
|
||||
if end > len(intVals) {
|
||||
end = len(intVals)
|
||||
}
|
||||
group := make([]int, end-i)
|
||||
copy(group, intVals[i:end])
|
||||
// Convert to interface{} for JSON serialization
|
||||
groupIf := make([]interface{}, len(group))
|
||||
for j, v := range group {
|
||||
groupIf[j] = v
|
||||
}
|
||||
result = append(result, groupIf)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@ -74,7 +74,12 @@ func Rerank(
|
||||
if useInfinity {
|
||||
// For Infinity: scores are already normalized before fusion
|
||||
// Just extract the scores from results
|
||||
return RerankInfinityFallback(sres)
|
||||
// Check if there are results to rerank
|
||||
if resp == nil || resp.Total == 0 || len(resp.Chunks) == 0 {
|
||||
return []float64{}, []float64{}, []float64{}
|
||||
}
|
||||
|
||||
return RerankInfinityFallback(resp)
|
||||
}
|
||||
|
||||
// For Elasticsearch: need to perform reranking
|
||||
@ -208,18 +213,26 @@ func RerankStandard(
|
||||
return HybridSimilarity(questionVector, insEmbd, keywords, insTw, tkWeight, vtWeight, qb)
|
||||
}
|
||||
|
||||
// RerankInfinityFallback extracts scores from Infinity search results
|
||||
// Infinity normalizes each way score before fusion, so we just extract them
|
||||
func RerankInfinityFallback(sres *SearchResult) (sim []float64, tsim []float64, vsim []float64) {
|
||||
sim = make([]float64, len(sres.IDs))
|
||||
for i, id := range sres.IDs {
|
||||
if fields := sres.Field[id]; fields != nil {
|
||||
if score, ok := fields["_score"].(float64); ok {
|
||||
// RerankInfinityFallback is used as a fallback when no reranker model is provided for Infinity engine.
|
||||
// Infinity can return scores in various field names (SCORE, score, SIMILARITY, etc.),
|
||||
// so we check multiple possible field names. If no score is found, we default to 1.0
|
||||
// to ensure the chunk passes through any similarity threshold filters.
|
||||
func RerankInfinityFallback(resp *engine.SearchResponse) (sim []float64, tsim []float64, vsim []float64) {
|
||||
sim = make([]float64, len(resp.Chunks))
|
||||
for i, chunk := range resp.Chunks {
|
||||
scoreFound := false
|
||||
scoreFields := []string{"SCORE", "score", "SIMILARITY", "similarity", "_score", "score()", "similarity()"}
|
||||
for _, field := range scoreFields {
|
||||
if score, ok := chunk[field].(float64); ok {
|
||||
sim[i] = score
|
||||
scoreFound = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !scoreFound {
|
||||
sim[i] = 1.0
|
||||
}
|
||||
}
|
||||
// For Infinity, tsim and vsim are the same as overall similarity
|
||||
return sim, sim, sim
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user