2

有什么办法可以让 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 索引这些数据吗?

4

3 回答 3

2

几个月前我有一个这样的问题。我的解决方案是使用 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。它支持开箱即用的嵌套文档。

于 2013-11-25T13:09:54.107 回答
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"
    ]
}
于 2014-07-14T10:49:25.743 回答
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"
            }

然后索引字段

title.FR:"这是 FR 标题"titles.EN:"这是EN 标题"

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

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

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

请注意,我已经针对 solr 4.9.0 进行了测试

M。

于 2014-08-21T12:42:10.693 回答