错误:未知类型 Go

huangapple go评论86阅读模式
英文:

Error unknown type Go

问题

这段代码是用于将MySQL数据加载到Redis集群中的。根据你提供的信息,你遇到了一个错误,错误信息是"hmset error: Do: unknown type map[string]string"。这个错误是因为在执行HMSET命令时,传递了一个未知类型的map[string]string参数。

根据代码,可以看到在RedisTask结构体中有一个MapData字段,用于存储要插入Redis的哈希表数据。在执行HMSET命令时,将MapData作为参数传递给client.Do函数。然而,根据错误信息,似乎client.Do函数无法处理map[string]string类型的参数。

要解决这个问题,你可以尝试使用redis.Args将map[string]string类型的参数转换为适当的格式。具体做法是将map[string]string类型的参数转换为redis.Args类型的参数,然后将转换后的参数传递给client.Do函数。

你可以尝试修改RedisTask结构体的Execute方法,如下所示:

func (e RedisTask) Execute() {
    log.Println("executing:", e.Key, ",", e.Index)

    if e.Command == "SET" {
        _, err := redis.String(client.Do("SET", e.Key, e.Value))
        checkErr(err, "set error:")
    } else if e.Command == "SADD" {
        _, err := redis.Strings(client.Do("SADD", e.Key, e.Value))
        checkErr(err, "sadd error:")
    } else if e.Command == "HMSET" {
        args := redis.Args{}.Add(e.Key).AddFlat(e.MapData)
        _, err := redis.String(client.Do("HMSET", args...))
        checkErr(err, "hmset error:")
    }
    // TODO: clean data
}

通过使用redis.Args{}.Add(e.Key).AddFlat(e.MapData)将map[string]string类型的参数转换为适当的格式,然后将转换后的参数传递给client.Do函数。

希望这可以解决你的问题!如果还有其他问题,请随时提问。

英文:

i'm really new to Go, su just bear with me here. I'm trying to write a code for loading mysql data to redis cluster using following :redis-go-cluster,
load2redis

This is the code. Its a little bit long, just bear with me here.

package main

import (
	"bytes"
	"database/sql"
	"flag"
	// "github.com/garyburd/redigo/redis"
	_ "github.com/go-sql-driver/mysql"
	//"gopkg.in/redis.v4"
	"github.com/chasex/redis-go-cluster"
	"log"
	"runtime"
	// "strings"
	"sync"
	"time"
	
)

var client *redis.Cluster

type Task interface {
	Execute()
}

type Pool struct {
	mu sync.Mutex

	size  int
	tasks chan Task
	kill  chan struct{}
	wg    sync.WaitGroup
}

func NewPool(size int) *Pool {
	pool := &Pool{
		tasks: make(chan Task, 128),
		kill:  make(chan struct{}),
	}
	pool.Resize(size)
	return pool
}

func (p *Pool) worker() {
	defer p.wg.Done()
	for {
		select {
		case task, ok := <-p.tasks:
			if !ok {
				return
			}
			task.Execute()
		case <-p.kill:
			return
		}
	}
}

func (p *Pool) Resize(n int) {
	p.mu.Lock()
	defer p.mu.Unlock()
	for p.size < n {
		p.size++
		p.wg.Add(1)
		go p.worker()
	}
	for p.size > n {
		p.size--
		p.kill <- struct{}{}
	}
}

func (p *Pool) Close() {
	close(p.tasks)
}

func (p *Pool) Wait() {
	p.wg.Wait()
}

func (p *Pool) Exec(task Task) {
	p.tasks <- task
}

type RedisTask struct {
	Index   int
	Command string
	Key     string
	Value   string
	MapData map[string]string
}

func (e RedisTask) Execute() {
	log.Println("executing:", e.Key, ",", e.Index)

	if e.Command == "SET" {
		_,err := redis.String(client.Do("SET", e.Key, e.Value))
		checkErr(err, "set error:")
	} else if e.Command == "SADD" {
		_,err := redis.Strings(client.Do("SADD", e.Key, e.Value))
		checkErr(err, "sadd error:") 
	} else if e.Command == "HMSET" {
		_,err := redis.StringMap(client.Do("HMSET", e.Key, e.MapData))
		checkErr(err, "hmset error:")
	}
	// TODO: clean data
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())
	startTime := time.Now().UnixNano() / int64(time.Millisecond)
	host := flag.String("s", "localhost:3306", "mysql server host and port ,eg localhost:3306")
	username := flag.String("u", "test", "username to login mysql")
	password := flag.String("p", "test", "password for mysql")
	database := flag.String("d", "test", "database you want to execute query")
	query := flag.String("q", "select 1;", "your query sql")
	ds := flag.String("ds", "key", "redis structure")
	PK := flag.String("pk", "Rkey", "the redis Key in the fields of mysql query result")

	//redisHost := flag.String("rs", "localhost:6379", "redis host and port ,eg localhost:6379")
	//redisPassword := flag.String("rp", "test", "redis password")

	poolSize := flag.Int("size", 10000, "redis pool size")

	flag.Parse()
	var buf bytes.Buffer = bytes.Buffer{}
	buf.WriteString(*username)
	buf.WriteString(":")
	buf.WriteString(*password)
	buf.WriteString("@tcp(")
	buf.WriteString(*host)
	buf.WriteString(")/")
	buf.WriteString(*database)

	db, err := sql.Open("mysql", buf.String())
	checkErr(err, "connect to mysql error !")
	defer db.Close()

	poolWorker := NewPool(*poolSize)

	// Execute the query
	rows, err := db.Query(*query)
	checkErr(err, "execute sql error!")

	// pool = newPool(*redisHost, *redisPassword, *poolSize)

	//client = redis.NewClient(&redis.Options{
	//	Addr:     *redisHost,
	//	Password: *redisPassword, // no password set
	//	DB:       0,              // use default DB
	//})
	
	client,_ = redis.NewCluster(&redis.Options{
			StartNodes: []string{"10.x.x.x:6000", "10.x.x.x:6001", "10.x.x.x:6002"},
			ConnTimeout: 50 * time.Millisecond,
			ReadTimeout: 50 * time.Millisecond,
			WriteTimeout: 50 * time.Millisecond,
			KeepAlive: 16,
			AliveTime: 60 * time.Second,
    })
	//checkErr(err, "client error:")

	//pong, err := client.Ping().Result()
	//checkErr(err, "redis client error:")
	//log.Println(pong)

	columns, err := rows.Columns()
	checkErr(err, "get columns error!")

	length := len(columns)
	values := make([]sql.RawBytes, length)

	scanArgs := make([]interface{}, len(values))
	for i := range values {
		scanArgs[i] = &values[i]
	}

	count := 0
	for rows.Next() {
		count += 1
		err = rows.Scan(scanArgs...)
		checkErr(err, "scan error")

		var value string
		var key string

		var task RedisTask

		if *ds == "key" {
			key = getStringData(values[0])
			value = getStringData(values[1])
			if value != "" {
				task = RedisTask{
					Index:   count,
					Command: "SET",
					Key:     key,
					Value:   value,
				}
			}
		} else if *ds == "set" {
			key = getStringData(values[0])
			value = getStringData(values[1])
			if value != "" {
				task = RedisTask{
					Index:   count,
					Command: "SADD",
					Key:     key,
					Value:   value,
				}
			}
		} else if *ds == "hash" {
			key = getStringData(values[0])
			// args := redis.Args{}.Add(key)

			m := make(map[string]string)

			for i, col := range values {
				if col != nil && columns[i] != *PK {
					value = getStringData(col)
					m[columns[i]] = value
				}
			}
			task = RedisTask{
				Index:   count,
				Command: "HMSET",
				Key:     key,
				MapData: m,
			}
		}
		poolWorker.Exec(task)
	}
	if err = rows.Err(); err != nil {
		panic(err.Error()) // proper error handling instead of panic in your app
	}

	poolWorker.Close()

	poolWorker.Wait()

	EndTime := time.Now().UnixNano() / int64(time.Millisecond)
	log.Println("======================================== executing time:", EndTime-startTime, " ms, total:", count)
}

func getStringData(data sql.RawBytes) string {
	if data == nil {
		return ""
	}
	value := string(data)
	return clearBad(value)
}

func clearBad(str string) string {
	// str = strings.Trim(str, "`")
	// str = strings.Trim(str, "ï½€")
	// str = strings.Trim(str, "-")
	// str = strings.Trim(str, ".")
	// str = strings.Trim(str, " ")
	// str = strings.Trim(str, ";")
	// str = strings.Trim(str, ",")
	// str = strings.Trim(str, ":")
	// str = strings.Trim(str, ";")
	// str = strings.Trim(str, "'")
	// str = strings.Trim(str, "!")
	return str
}

func checkErr(err error, msg string) {
	if err != nil {
		log.Fatalln(msg, err)
	}
}

When i'm executing it, i'm getting following exception:

./rak -u user -p user -s 10.X.X.X:8080 -d test -q "SELECT CONCAT( 'student:', c.sid ) Rkey, c.sname SNAME, c.saddress SADDRESS, c.sage SAGE FROM STUDENT c WHERE c.sid  > 0;" -ds hash -size 1200
2017/07/21 10:29:09 rak.go:93: executing: student:2 , 2
2017/07/21 10:29:09 rak.go:93: executing: student:1 , 1
2017/07/21 10:29:09 rak.go:93: executing: student:3 , 3
2017/07/21 10:29:09 rak.go:268: hmset error: Do: unknown type map[string]string
$

Can somebody explain to me what i'm doing wrong here? I'd be very grateful.

答案1

得分: 1

Do函数参数的可接受值为int64float64string[]byte。由于您传递了一个map,所以出现了错误unknown type %T

这是相应代码的参考链接:

redis-go-cluster/node.go

英文:

Accepted values for Do function arguements are int64, float64, string or []byte .Since you passed a map it failed with error unknown type %T

Here is a reference to the respective code that does it

redis-go-cluster/node.go

答案2

得分: 1

如前所述,Do 方法不能与映射(maps)一起使用。以下是修复此问题的一种方法。

} else if e.Command == "HMSET" {
    // 构建一个字符串切片来保存键值对
    args := make([]string, 0, len(e.MapData) * 2)
    for k, v := range e.MapData {
        args = append(args, k, v)
    }
    _, err := redis.StringMap(client.Do("HMSET", e.Key, args...))
    checkErr(err, "hmset error:")
}

Do 方法对应于 Redis 命令集,参数的使用方式也是相同的。例如:

127.0.0.1:6379> HMSET myKey foo bar baz boff
OK
127.0.0.1:6379> HGETALL myKey
1) "foo"
2) "bar"
3) "baz"
4) "boff"
127.0.0.1:6379>

在你的代码中,使用 Redis 客户端进行相同的映射设置操作将是:

client.Do("HMSET", "myKey", "foo", "bar", "baz", "boff")

当映射的键和值的参数是动态的时候,最直接的方式是:

client.Do("HMSET", "myKey", []string{"foo", "bar", "baz", "boff"}...)

这正是上面第一个代码块所做的。

英文:

As pointed out, Do does not work with maps. This is one way you could fix it.

} else if e.Command == "HMSET" {
    // Build up a string slice to hold the key value pairs
    args := make([]string, 0, len(e.MapData) * 2)
    for k, v := range e.MapData {
        args = append(args, k, v)
    }
    _,err := redis.StringMap(client.Do("HMSET", e.Key, args...))
    checkErr(err, "hmset error:")
}

The Do method maps to the Redis command set and arguments are expected in the same way. For example.

127.0.0.1:6379> HMSET myKey foo bar baz boff
OK
127.0.0.1:6379> HGETALL myKey
1) "foo"
2) "bar"
3) "baz"
4) "boff"
127.0.0.1:6379>

The same map-set operation using the redis client in your code would be

client.Do("HMSET", "myKey", "foo", "bar", "baz", "boff")

When the arguments for keys and values of the map are dynamic, the most straight forward way is

client.Do("HMSET", "myKey", []string{"foo", "bar", "baz", "boff"}...)

which is exactly what the first code block above does.

huangapple
  • 本文由 发表于 2017年7月21日 22:49:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/45240642.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定