使用Solr索引嵌入的mongoDB文档(在数组中)

时间:2013-10-08 23:47:34

标签: mongodb solr indexing

有什么办法,我怎样才能使Solr索引嵌入mongoDB文件?我们已经可以通过mongo-connector索引mongo文档中键的顶级值,将数据推送到Solr。

然而,在这种代表帖子的结构中:

{
   author: "someone", 
   post_text : "some really long text which is already indexed by solr",
   comments : [
        {
            author:"someone else"
            comment_text:"some quite long comment, which I do not 
                          know how to index in Solr"
        },
        {
            author:"me"
            comment_text:"another quite long comment, which I do not 
                          know how to index in Solr"
        }
   ]
}

这只是一个示例结构。在我们的项目中,我们处理更复杂的结构,有时,我们要索引的文本嵌套在第二级或第三级(深度,或者它的正式名称)。

我相信有一个mongoDB + Solr用户社区,所以这个问题必须先解决,但我无法找到好的材料,这会解决这个问题,如果有一个很好的方法,怎么样处理这个或者是否没有解决方案和解决方法尚未建立(也许你可以为我提供一个)

为了更好地理解,我们的一个结构具有顶级键,其值为一个包含几个分析结果的数组,其中一个具有奇异值数组,这些数组是结果的一部分。我们需要索引这些值。例如。 (这不是我们使用的实际数据结构):

{... 
    Analysis_performed: [
        {
            User_tags: 
                [
                   {
                       tag_name: "awesome", 
                       tag_score: 180
                   },
                   {
                       tag_name: "boring", 
                       tag_score: 10
                   }
                ]
        }
    ]
}

在这种情况下,我们需要索引标记名称。我们有可能存储数据的结构不好,我们想存储,但我们认真思考它,我们认为它非常好。但是,即使我们切换到较少嵌套的信息,我们也很可能遇到至少一种情况,我们必须索引存储在数组中的嵌入文档中的信息,这是问题的主要焦点。我们能用某种方式用SOLR索引这样的数据吗?

3 个答案:

答案 0 :(得分:1)

几个月前我有这样的问题。我的解决方案是使用doc_manager。 您可以使用solr_doc_manager(upsert方法)来修改发布到solr的文档。例如,如果你有

ACL: {
    Read: [ id1, id2 ...  ]
}

你可以像

那样处理它
def upsert(self, doc):
    if ("ACL" in doc) and ("Read" in doc["ACL"]):
        doc["ACL.Read"] = []
        for item in doc["ACL"]["Read"]:
            if not isinstance(item, dict):
                id = ObjectId(item)
                doc["ACL.Read"].append(str(id))
    self.solr.add([doc], commit=False)

它添加了新字段 - ACL.Read。该字段是多值的,并存储来自ACL的ID列表:{Read:[...]}

如果您不想为嵌套文档编写自己的处理程序,可以尝试另一个mongo连接器。 Github项目页面https://github.com/SelfishInc/solr-mongo-connector。它支持开箱即用的嵌套文档。

答案 1 :(得分:1)

官方10gen mongo连接器现在支持展平数组和索引子文档。 见https://github.com/10gen-labs/mongo-connector

然而对于数组来说,它会做出像这样令人不快的事情。它将改变这份文件:

{ 
    "hashtagEntities" : [
        {
                "start" : "66",
                "end" : "81",
                "text" : "startupweekend"
        },
        {
                "start" : "82",
                "end" : "90",
                "text" : "startup"
        },
        {
                "start" : "91",
                "end" : "100",
                "text" : "startups"
        },
        {
                "start" : "101",
                "end" : "108",
                "text" : "london"
        }
    ]
}

进入这个:

{
    "hashtagEntities.0.start" : "66",
    "hashtagEntities.0.end" : "81",
    "hashtagEntities.0.text" : "startupweekend",
    "hashtagEntities.1.start" : "82",
    "hashtagEntities.1.end" : "90",
    "hashtagEntities.1.text" : "startup",
....
}

以上很难在Solr中编制索引 - 如果您的文档没有稳定的架构,则更是如此。我们想要更像这样的东西:

{
    "hashtagEntities.xArray.start": [
      "66",
      "82",
      "91",
      "101"
    ],
    "hashtagEntities.xArray.text": [
      "startupweekend",
      "startup",
      "startups",
      "london"
    ],
    "hashtagEntities.xArray.end": [
      "81",
      "90",
      "100",
      "108"
    ],
}

我已经实现了另一种solr_doc_manager.py

如果您想使用它,只需将doc_manager中的flatten_doc函数编辑为此,以支持此功能:

def flattened(doc):
    return dict(flattened_kernel(doc, []))
def flattened_kernel(doc, path):
    for k, v in doc.items():
        path.append(k)
        if isinstance(v, dict):
            for inner_k, inner_v in flattened_kernel(v, path):
                yield inner_k, inner_v
        elif isinstance(v, list):
            for inner_k, inner_v in flattened_list(v, path).items():
                yield inner_k, inner_v
            path.pop()
        else:
            yield ".".join(path), v
        path.pop()        
def flattened_list(v, path):
    tem = dict()
    #path2 = list()
    path.append(str("xArray"))            
    for li, lv in enumerate(v):                
        if isinstance(lv, dict):
            for dk, dv in flattened_kernel(lv, path):
                got = tem.get(dk, list())
                if isinstance(dv, list):
                    got.extend(dv)
                else:
                    got.append(dv)
                tem[dk] = got
        else:
            got = tem.get(".".join(path)+".ROOT", list())
            if isinstance(lv, list):
                got.extend(lv)
            else:
                got.append(lv)
            tem[".".join(path)+".ROOT"] = got
    return tem

如果您不想丢失数组(不是子文档)中的数据,此实现会将数据放入" array.ROOT"属性。见这里:

{
    "array" : [
            {
                    "innerArray" : [
                            {
                                    "c" : 1,
                                    "d" : 2
                            },
                            {
                                    "ahah" : "asdf"
                            },
                            42,
                            43
                    ]
            },
            1,
            2
    ],
}

进入:

{
    "array.xArray.ROOT": [
      "1.0",
      "2.0"
    ],
    "array.xArray.innerArray.xArray.ROOT": [
      "42.0",
      "43.0"
    ],
    "array.xArray.innerArray.xArray.c": [
      "1.0"
    ],
    "array.xArray.innerArray.xArray.d": [
      "2.0"
    ],
    "array.xArray.innerArray.xArray.ahah": [
      "asdf"
    ]
}

答案 2 :(得分:0)

我有同样的问题,我想索引/存储在Solr复杂的文档中。我的方法是修改JsonLoader以接受带有数组/对象作为值的复杂json文档。

它存储对象/数组,然后将其展平并为字段编制索引。

例如基本示例文档

   {
        "titles_json":{"FR":"This is the FR title" , "EN":"This is the EN title"} ,
        "id": 1000003,
        "guid": "3b2f2998-85ac-4a4e-8867-beb551c0b3c6"
   }

它将存储

titles_json:{
               "FR":"This is the FR title" , 
               "EN":"This is the EN title"
            }

然后索引字段

titles.FR:“这是FR标题” titles.EN:“这是EN标题”

您不仅可以索引子文档,而且当您在solr上执行搜索时,您将收到索引文档的原始复杂结构。

如果您想查看现有solr的源代码,安装和集成详细信息,请检查

http://www.solrfromscratch.com/2014/08/20/embedded-documents-in-solr/

请注意我已经为solr 4.9.0测试了这个

微米。