2013-10-08 4 views
0

Есть ли способ, как я могу сделать документы Solr вложенными mongoDB? Мы уже можем индексировать значения верхнего уровня ключей в документе mongo через mongo-коннектор, толкаем данные в Solr.Индексирование встроенных документов mongoDB (в массиве) с помощью 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?

ответ

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

Если вы хотите использовать это, просто изменить функцию flatten_doc в вашем doc_manager к этому, чтобы поддержать такую ​​функциональность:

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" 
    ] 
} 
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: {Read: [...]}

Если вы не хотите писать собственные обработчики для вложенных документов, вы можете попробовать другой соединитель mongo. Страница проекта Github https://github.com/SelfishInc/solr-mongo-connector. Он поддерживает вложенные документы из коробки.

+0

Итак, мы думаем об использовании этого разъема в производственной среде - как вы думаете, проект в порядке и надежен? Используется ли он где-то еще в производстве? – Ev0oD

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:"This является название FR " titles.EN:" Это название EN "

Не только вы сможете проиндексировать ребенка cuments, но также при выполнении поиска по solr вы получите оригинальную сложную структуру документа, которую вы проиндексировали.

Если вы хотите проверить исходный код, установке и интеграции детали с существующей Solr, проверьте

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

Обратите внимание, что я испытал это на Solr 4.9.0

М.

+0

В чем разница между вашим решением и тем, как соединитель mongo выравнивает поддокументы и массивы в текущей версии? – Ev0oD

+0

Извините, я никогда не работал с коннектором mongo, но думаю, что он сглаживает json, а затем отправляет его в solr. В моем решении вы делаете то же самое, но также сохраняете исходную структуру json-документа в ответе. Кроме того, вы можете импортировать данные json извне не только mongo [я импортирую из db]. – Michael

Смежные вопросы