Riak Java无法从Scala中的MapReduce查询反序列化域对象?

Riak Java无法从Scala中的MapReduce查询反序列化域对象?,java,scala,riak,domain-object,Java,Scala,Riak,Domain Object,在简单bucket上执行MapReduce查询。出于某种原因,我从Jackson那里得到了一个例外: Caused by: org.codehaus.jackson.map.JsonMappingException: Can not deserialize instance of com.threetierlogic.AccountService.models.User out of START_ARRAY token at [Source: java.io.StringReader@3949

在简单bucket上执行MapReduce查询。出于某种原因,我从Jackson那里得到了一个例外:

Caused by: org.codehaus.jackson.map.JsonMappingException: Can not deserialize instance of com.threetierlogic.AccountService.models.User out of START_ARRAY token
 at [Source: java.io.StringReader@39494ff0; line: 1, column: 2]
        at org.codehaus.jackson.map.JsonMappingException.from(JsonMappingException.java:163)
        at org.codehaus.jackson.map.deser.StdDeserializationContext.mappingException(StdDeserializationContext.java:219)
        at org.codehaus.jackson.map.deser.StdDeserializationContext.mappingException(StdDeserializationContext.java:212)
        ... 179 more
下面是我正在执行的MapReduce查询:

DB.client.mapReduce(bucketName)
    .addReducePhase(NamedErlangFunction.REDUCE_IDENTITY)
    .execute().getResult(classOf[User])
现在,如果我使用
getResultRaw()
调用JSON,它将返回一个JSON字符串,该字符串不包含值,只包含键:

[["accounts-user","8f0bb6e41592690d701225e263807a5e"],["accounts-user","2687cf9444013c45ba2637e9f6d3d3ad"],["accounts-user","3507e2e1f3d2818fdd276214d594c8e"],["accounts-user","fd186b0293ab7eb737f8b66e353fe4a6"],["accounts-user","bf6ce6bca0f642abfe74f2e2281e676c"],["accounts-user","b58d356551a8df6d3bbaf65e577f4b12"],["accounts-user","8126d599d259fd43f701c90787096049"],["accounts-user","33b9ae3befb23b7030b609158bb762d"],["accounts-user","770a897d5ce8c8e118ae121fc01f4c80"],["accounts-user","edae605390c35256b5df055f5574734d"],["accounts-user","ef19ad34a2be4ab8de111d1590a8768b"],["accounts-user","89a9f29ac937595038d37169f9ba7c8"],["accounts-user","85be26f43f7bb74eefa7683dcc74c555"]]
那么,我在这里忽略了什么?我是否需要调用某种域转换器,还是MapReduce查询本身存在问题

编辑 如果有帮助,下面是我如何在Riak中存储
IRiakObjects

def store(o: User) = bucket.store(o).withConverter(new UserConverter(bucketName)).execute()

注释中提到的第一个问题是,
REDUCE\u IDENTITY
返回的bucket/key对列表不是您想要的。第二个问题是。。。如果您存储的不是JSON,就不能直接从mapreduce转到POJO。第三个问题是。。。Riak mapreduce并不是为二进制值而设计的

下面使用的
KryoPersonConverter
Person
类演示了如何在自定义转换器中使用Kryo

我要开始编写示例代码并内联我的注释:

public class App 
{
    public static void main( String[] args ) throws RiakException
    {
        List<Person> personList = new ArrayList<Person>();

        Person p = new Person("Bob","111 Elm Street","555-1212");
        personList.add(p);
        p = new Person("Jenny","122 Spruce Lane","867-5309");
        personList.add(p);
        p = new Person("Steve","333 Oak place","555-1111");
        personList.add(p);


        IRiakClient client = RiakFactory.pbcClient();
        Bucket b = client.fetchBucket("people").execute();
        KryoPersonConverter converter = new KryoPersonConverter("people");

        for (Person p2 : personList)
        {
            b.store(p2).withConverter(converter).execute();
        }

        p = new Person();
        p.setName("Jenny");
        p = b.fetch(p).withConverter(converter).execute();
        assert(p.getPhone().equals("867-5309")); // I got your number
这里我们看到了问题,因为
println()
的输出是:

["\u0001\u0001\u000e111 Elm Street\u0001\u0003Bob\u0001\b555-1212","\u0001\u0001\r333 Oak place\u0001\u0005Steve\u0001\b555-1111","\u0001\u0001\u000f122 Spruce Lane\u0001\u0005Jenny\u0001\b867-5309"]
不幸的是,Riak中的mapreduce实际上是用来处理JSON数据(或者只是简单的字符串)的。我们有一个JSON数组,其中包含存储的字节的JSON字符串

要使用它,您必须将
字符串
作为
集合
,然后使用Kryo转换字节

        Collection<String> objects = result.getResult(String.class);


        Kryo kryo = new Kryo();
        kryo.register(Person.class);
        ObjectBuffer buffer = new ObjectBuffer(kryo);

        for (String s : objects)
        {
            Person p3 = buffer.readObject(s.getBytes(), Person.class);
            System.out.println(p3.getName() + " " + p3.getPhone());
        }

        client.shutdown();     
    }
}
Collection objects=result.getResult(String.class);
Kryo Kryo=新Kryo();
注册号(人.类);
ObjectBuffer=新的ObjectBuffer(kryo);
用于(字符串s:对象)
{
Person p3=buffer.readObject(s.getBytes(),Person.class);
System.out.println(p3.getName()+“”+p3.getPhone());
}
client.shutdown();
}
}
您将得到输出:

鲍勃555-1212
史蒂夫555-1111
珍妮867-5309


注释中提到的第一个问题是,
REDUCE\u IDENTITY
返回的bucket/key对列表不是您想要的。第二个问题是。。。如果您存储的不是JSON,就不能直接从mapreduce转到POJO。第三个问题是。。。Riak mapreduce并不是为二进制值而设计的

下面使用的
KryoPersonConverter
Person
类演示了如何在自定义转换器中使用Kryo

我要开始编写示例代码并内联我的注释:

public class App 
{
    public static void main( String[] args ) throws RiakException
    {
        List<Person> personList = new ArrayList<Person>();

        Person p = new Person("Bob","111 Elm Street","555-1212");
        personList.add(p);
        p = new Person("Jenny","122 Spruce Lane","867-5309");
        personList.add(p);
        p = new Person("Steve","333 Oak place","555-1111");
        personList.add(p);


        IRiakClient client = RiakFactory.pbcClient();
        Bucket b = client.fetchBucket("people").execute();
        KryoPersonConverter converter = new KryoPersonConverter("people");

        for (Person p2 : personList)
        {
            b.store(p2).withConverter(converter).execute();
        }

        p = new Person();
        p.setName("Jenny");
        p = b.fetch(p).withConverter(converter).execute();
        assert(p.getPhone().equals("867-5309")); // I got your number
这里我们看到了问题,因为
println()
的输出是:

["\u0001\u0001\u000e111 Elm Street\u0001\u0003Bob\u0001\b555-1212","\u0001\u0001\r333 Oak place\u0001\u0005Steve\u0001\b555-1111","\u0001\u0001\u000f122 Spruce Lane\u0001\u0005Jenny\u0001\b867-5309"]
不幸的是,Riak中的mapreduce实际上是用来处理JSON数据(或者只是简单的字符串)的。我们有一个JSON数组,其中包含存储的字节的JSON字符串

要使用它,您必须将
字符串
作为
集合
,然后使用Kryo转换字节

        Collection<String> objects = result.getResult(String.class);


        Kryo kryo = new Kryo();
        kryo.register(Person.class);
        ObjectBuffer buffer = new ObjectBuffer(kryo);

        for (String s : objects)
        {
            Person p3 = buffer.readObject(s.getBytes(), Person.class);
            System.out.println(p3.getName() + " " + p3.getPhone());
        }

        client.shutdown();     
    }
}
Collection objects=result.getResult(String.class);
Kryo Kryo=新Kryo();
注册号(人.类);
ObjectBuffer=新的ObjectBuffer(kryo);
用于(字符串s:对象)
{
Person p3=buffer.readObject(s.getBytes(),Person.class);
System.out.println(p3.getName()+“”+p3.getPhone());
}
client.shutdown();
}
}
您将得到输出:

鲍勃555-1212
史蒂夫555-1111
珍妮867-5309


NamedErlangFunction.REDUCE_IDENTITY
返回一个bucket/key对列表(如您所见,它被转换为包含多个数组的JSON数组,每个数组都有一个bucket和key)。我怀疑你在试图得到其他东西。这可能是一个概念上的误解(仍在学习)。但是,
NamedJSFunction(“Riak.mapValuesJson”)
是否返回对象值?如果是这样的话,那么我仍然会出错。有没有相关的文档链接可以共享?我查了一下:我按照Riak java Github中的步骤创建了一个DomainConverter。我猜这两种方法是不兼容的?你到底想做什么?把所有的东西都从桶里拿出来?没错。我仍然在思考MapReduce,但似乎使用kryo序列化域对象需要不同的方法来提取对象?
NamedErlangFunction.REDUCE_IDENTITY
返回bucket/key对列表(如您所见,它被转换为包含多个数组的JSON数组,每个数组都有一个bucket和key). 我怀疑你在试图得到其他东西。这可能是一个概念上的误解(仍在学习)。但是,
NamedJSFunction(“Riak.mapValuesJson”)
是否返回对象值?如果是这样的话,那么我仍然会出错。有没有相关的文档链接可以共享?我查了一下:我按照Riak java Github中的步骤创建了一个DomainConverter。我猜这两种方法是不兼容的?你到底想做什么?把所有的东西都从桶里拿出来?没错。我仍然在思考MapReduce,但似乎使用kryo序列化域对象需要使用不同的方法来提取对象?这就是总结。使用POJO和JSON的一个很好的理由;)但愿我从一开始就意识到这一点。然而,我确实从你的回答中学到了很多,我敢打赌这在今后的道路上会派上用场。另一方面,非常感谢您的大力支持!这有点有用。。如果您的mapreduce作业只关注关键点,那么这不是一个问题(您会想到关键点的子集)。唯一真正的问题是
MapReduceResult
没有任何方法传递转换器,这只是客户端设计的一个缺点。类似于
Collection c=result.getResult(Person.class,converter)
的东西会很多