【问题标题】:Indexing embedded mongoDB documents (in an array) with Solr使用 Solr 索引嵌入式 mongoDB 文档(在数组中)
【发布时间】:2013-10-16 03:11:36
【问题描述】:

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

【问题讨论】:

    标签: mongodb solr indexing


    【解决方案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。它支持开箱即用的嵌套文档。

    【讨论】:

    • 所以我们正在考虑在生产环境中使用这个连接器——你认为这个项目是好的和可靠的吗?它是否在生产中的其他地方使用?
    【解决方案2】:

    官方 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"
        ]
    }
    

    【讨论】:

      【解决方案3】:

      我有同样的问题,我想索引/存储在 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 标题" title.EN:"这是英文标题"

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

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

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

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

      M.

      【讨论】:

      • 您的解决方案与当前版本中 mongo 连接器展平子文档和数组的方式有什么区别?
      • 对不起,我从来没有使用过 mongo 连接器,但我猜它正在压平 json,然后将其发送到 solr。在我的解决方案中,你做同样的事情,但你在响应中保留了 json 文档的原始结构。此外,您可以从任何地方导入 json 数据,而不仅仅是 mongo [我正在从 db 导入]。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多