2014-01-22 3 views
5

Я хочу создать приложение, в котором соответствие требует, чтобы каждый токен в документе содержался в запросе хотя бы один раз !!!Elasticsearch - проверить, содержится ли документ в запросе с использованием синонимов

Обратите внимание, что это наоборот, чем стандартное ожидание. Таким образом, документы сейчас довольно малы, а запросы могут быть очень длинными. Пример:

Документ:

"elastic super cool". 

Действительный матч запрос будет

"I like elastic things since elasticsearch is super cool" 

мне удалось получить количество соответствующих лексем из упругого поиска (смотри также https://groups.google.com/forum/?fromgroups=#!topic/elasticsearch/ttJTE52hXf8). Таким образом, в приведенном выше примере 3 соответствия (= длина документа) означают, что запрос совпадает.

Но как я могу объединить это с синонимами ???

Предположим, что синоним "cool" будет "nice", "great" и "good". Используя синонимный токен-фильтр, мне удалось добавить синоны в каждую позицию документа.

Таким образом, следующие четыре документа имеют 3 лексема соответствует для указанного выше запроса:

"elastic super nice" 

"elastic nice cool" 

"nice good great" 

"good great cool" 

Но только первый матч является действительным матч!

Как я могу избежать того, что каждое совпадение синонима считается одним совпадением, хотя они представляют один и тот же токен в документе?

Любые идеи, как решить эту проблему?

Я читал, что перколаторы могли бы решить эту проблему, но я до сих пор не уверен, будет ли perculators работать с синонимами, как я хочу его ...

Идей?

+0

Вы смогли решить эту проблему? Вы пробовали Percolator с фильтром синонима? – vaidik

ответ

2

Я предполагаю, что вы расширите синонимы. Вы можете использовать скрипты для подсчета совпадающих позиций.

Elasticsearch Google Group with a solution by Vineeth Mohan

Я приспособил его сценарий как родной сценарий, который возвращает число в диапазоне от 0 до 1 для отношения соответствующих положений в этой области. Я оптимальной его немного, чтобы соответствовать только одну позицию за запрос

Вам нужно поле, которое содержит ряд позиций, например, с помощью token_count, который на самом деле подсчитывает количество позиций

@Override 
public Object run() 
{ 
    IndexField indexField = this.indexLookup().get(field); 
    Long numberOfPositions = ((ScriptDocValues.Longs) doc().get(positionsField)).getValue(); 

    ArrayList<Integer> positions = new ArrayList<Integer>(); 
    for (String term : terms) 
    { 
     Iterator<TermPosition> termPos = indexField.get(term, IndexLookup.FLAG_POSITIONS | IndexLookup.FLAG_CACHE) 
       .iterator(); 
     while (termPos.hasNext()) 
     { 
      int position = termPos.next().position; 
      if (positions.contains(position)) 
      { 
       continue; 
      } 
      positions.add(position); 
      // if the term matches multiple positions, only a new position should count 
      break; 
     } 
    } 

    return positions.size() * 1.0/numberOfPositions; 
} 

Вы можете, чем использование он в вашем запросе как скрипт function_score.

{ 
"function_score": { 
    "query": { 
     "match": { 
      "message": "I like elastic things since elasticsearch is super cool" 
     } 
    }, 
    "script_score": { 
     "params": { 
      "terms": [ 
       "I", 
       "like", 
       "elastic", 
       "things", 
       "since", 
       "elasticsearch", 
       "is", 
       "super", 
       "cool" 
      ], 
      "field": "message", 
      "positions_field": "message.pos_count" 
     }, 
     "lang": "native", 
     "script": "matched_positions_ratio" 
    }, 
    "boost_mode": "replace" 
} 
} 

Вы можете установить «min_score» в 1 и получить документы, соответствующие всем позициям в данном поле.

Я надеюсь, что это решение - это то, что вам нужно.

+0

Это похоже на обычный вариант использования. Есть ли лучший (из коробки) способ справиться с этим сейчас, или нам нужно идти только с собственным скриптовым решением? –

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