2015-04-19 75 views
1

所有領域較少比方說,我有一個MongoDB的查詢,看起來像這樣:匹配比MongoDB的

result = db.collection.find(
    { 
     'fruit_type': 'apple', 
     'fruit_name': 'macintosh' 
     'primary_color': 'red', 
     'sheen': 'glossy', 
     'origin_label': 'true', 
     'stem_present': 'true', 
     'stem_leaves_present': 'true', 
     'blemish': 'none', 
     'firmness': 'moderate' 
    } 
) 

這是很好,當我有完全符合這套標準,一些蘋果。然而,當我沒有符合這些標準時,我仍然想要蘋果。

比方說,唯一的強制性標準,這裏有'fruit_type': 'apple''primary_color': 'red'

至於其他,我想匹配多個標準,可以儘可能地在不知道的時候什麼最匹配可能會提前。這不是「模糊匹配」。這更像是按字段「不精確匹配」。

例如,與'sheen': 'matte'的結果,但與所有其他字段相同的值將是一個有效,但不精確的結果,給定沒有完全匹配。如果不精確,或者結果爲'stem_present': 'false'會很好。換句話說:如果我指定了8個字段和值,並且沒有完全匹配,但是與其中的7個匹配,與6匹配並且匹配5,我想要7(而不是其他的)。如果我在亞馬遜水果搜索框中輸入「red macintosh apple no stem leaves matte finish」,它仍會顯示我紅蘋果,即使它只有光澤的蘋果。這是我想在用戶級重現的效果(假設自然語言查詢可以完全呈現​​在Mongo的查詢語言中)。

一個解決方案可能是編寫一個巨大的指定所有排列的查詢,但假設我有30個字段和許多值。我不想提前指定所有內容,因爲我不知道提前出現的查詢字段組合。

是否有退避優美(高效的)方式或具體退回到MongoDB中不精確的結果嗎?或者是超出查詢範圍的解決方案?

+0

駕駛的downvotes沒有用。請解釋爲什麼這是一個糟糕的問題。 – bahmait

+0

我只能猜測,但有些人傾向於將JavaScript看作沒有真正的編程語言。 ;)我個人認爲這是一個有趣的問題。 –

+0

@MarkusWMahlberg謝謝,但不知道爲什麼這個問題給你帶來了JavaScript的問題。 – bahmait

回答

0

確保您至少滿足強制性條件的最接近的方法是將所有可選查詢字段與$or運算符中的一個必填字段放在一起,因爲它選擇了滿足至少一個可選的表情在$或運算符表達式:

result = db.collection.find(
    { 
     'fruit_type': 'apple',      
     "$or": [ 
      { 'primary_color': 'red' }, 
      { 'fruit_name': 'macintosh' }, 
      { 'sheen': 'glossy' }, 
      { 'origin_label': 'true' }, 
      { 'stem_present': 'true' }, 
      { 'stem_leaves_present': 'true' }, 
      { 'blemish': 'none' }, 
      { 'firmness': 'moderate' } 
     ] 
    } 
) 

上面的查詢將選擇集合中的所有文件,其中fruit_type字段值是蘋果和primary_color字段值等於紅色。如果在您的收藏中沒有primary_color字段值爲紅色的文檔,則上述內容不會返回任何文檔。

性能方面,考慮創建的兩個必填字段一個複合索引,如果他們是常用發出的查詢,因爲掃描索引比掃描收集快得多。

欲瞭解更多詳情,請閱讀文檔章節上Optimize Query PerformanceBehaviors - $or Clauses and Indexes

+0

「至少有一個」不是我要求的。請參閱我的修訂。 – bahmait

+0

@bahmait好的,你有沒有測試過上面的查詢? – chridam

+0

我很感謝您花時間回答。我的例子使用假數據,因爲我不能發佈真實的數據。如果我知道你的回答是基於Mongo的什麼屬性,我會構建自己的測試。如果Mongo自動使用大的'$或'來給出最接近的匹配,那麼知道這一點很有用。我原來的帖子提到'$或'作爲解決方案,但是假設我必須指定缺少字段的所有不同可能組合,以獲得最接近的匹配,因爲至少一個常常意味着:找到至少一個,然後停止。 – bahmait

1

下面是我在做什麼(在Python)作爲一個權宜的簡化版本。

首先,定義精確匹配(這也可以來上飛):

full_query = { 
    'fruit_type': 'apple', 
    'fruit_name': 'macintosh' 
    'primary_color': 'red', 
    'sheen': 'glossy', 
    'origin_label': 'true', 
    'stem_present': 'true', 
    'stem_leaves_present': 'true', 
    'blemish': 'none', 
    'firmness': 'moderate' 
} 

然後定義的基本領域 - 即必須在那裏不管是什麼領域。 (這在某種方式預先定義。)

essential_query = { 
    'fruit_type': 'apple', 
    'primary_color': 'red' 
} 

然後從基本查詢得到的所有比賽,並且比較:

def best_matches(full_query, essential_query): 
    items = db.collection.find(essential_query) 
    best_matches = defaultdict(list) 
    for item in items: 
     counter = 0 
     for key in full_query: 
      if full_query[key] == item.get(key): 
       counter += 1 
     best_matches[counter].append(item) 
    return best_matches 

然後你可以的,你得到了什麼鍵排序倒退:argmax鍵包含精確或最接近匹配的產品。 (你可以添加功能來告訴你它是什麼。)當你下降鍵時,匹配會變得更糟。還可以設想加權某些領域,鬆開平等檢查等

編輯:

這裏的另一種非理想的可能性,這將只工作,如果你預先計算的匹配和不關心表現。定義詳盡的訂購查詢字段的列表。

fields_essential_to_inessential = [ 
    'fruit_type', 
    'primary_color, 
    'sheen': 'glossy', 
    'origin_label', 
    'stem_present', 
    'stem_leaves_present', 
    'blemish', 
    'firmness', 
    'fruit_name' 
] 

當查詢進來時,嘗試一下。如果您沒有獲得threshold匹配數,請從其中一個字段中彈出,然後重試。

def compute_matches(full_query, fields_essential_to_inessential): 

    exists = set() 
    matches = [] 
    threshold = 20 

    while fields_essential_to_inessential: 
     query = {} 
     for key in fields_essential_to_inessential: 
      if full_query.get(key): 
       query[key] = full_query[key] 
     for item in db.products.find(query): 
      if item['item-id'] not in exists: 
       exists.add(item['item-id']) 
       matches.append(item) 
       if len(matches) == threshold: 
        return matches 
     fields_essential_to_inessential.pop() 

    return matches