elasticsearch: как ранжировать первые появляющиеся слова или фразы выше

Например, если у меня есть следующие документы:

1. Casa Road
2. Jalan Casa 

Скажем, мой термин запроса "cas"... при поиске оба документа имеют одинаковые оценки. Я хочу, чтобы тот, у которого casa, появлялся раньше (т.е. документ 1 здесь) и занимал первое место в выводе моего запроса.

Я использую анализатор edgeNGram. Также я использую агрегаты, поэтому я не могу использовать обычную сортировку, которая происходит после запроса.


person UD1989    schedule 22.09.2015    source источник


Ответы (2)


Вы можете использовать Bool Query элементы, которые начинаются с поискового запроса:

{
    "bool" : {
        "must" : {
            "match" : { "name" : "cas" }
        },
        "should": {
            "prefix" : { "name" : "cas" }
        },
    }
}

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

Как это работает:

  1. Оба документа будут соответствовать запросу в предложении must и получат за это одинаковую оценку. Документ не будет включен, если он не соответствует запросу must.
  2. Только документ с термином, начинающимся с cas, будет соответствовать запросу в предложении should, в результате чего он получит более высокий балл. Документ не будет исключен, если он не соответствует запросу should.
person Jrgns    schedule 25.09.2015

Это может быть немного сложнее, но это должно сработать. По сути, вам нужна позиция термина в самом тексте, а также количество терминов в тексте. Фактическая оценка рассчитывается с помощью сценариев, поэтому вам необходимо включить динамическое выполнение сценариев в elasticsearch.yml файле конфигурации:

script.engine.groovy.inline.search: on

Это то, что вам нужно:

  • сопоставление, использующее term_vector, установлено в with_positions, а edgeNGram и подполе типа token_count:
PUT /test
{
  "mappings": {
    "test": {
      "properties": {
        "text": {
          "type": "string",
          "term_vector": "with_positions",
          "index_analyzer": "edgengram_analyzer",
          "search_analyzer": "keyword",
          "fields": {
            "word_count": {
              "type": "token_count",
              "store": "yes",
              "analyzer": "standard"
            }
          }
        }
      }
    }
  },
  "settings": {
    "analysis": {
      "filter": {
        "name_ngrams": {
          "min_gram": "2",
          "type": "edgeNGram",
          "max_gram": "30"
        }
      },
      "analyzer": {
        "edgengram_analyzer": {
          "type": "custom",
          "filter": [
            "standard",
            "lowercase",
            "name_ngrams"
          ],
          "tokenizer": "standard"
        }
      }
    }
  }
}
  • тестовые документы:
POST /test/test/1
{"text":"Casa Road"}
POST /test/test/2
{"text":"Jalan Casa"}
  • сам запрос:
GET /test/test/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "function_score": {
            "query": {
              "term": {
                "text": {
                  "value": "cas"
                }
              }
            },
            "script_score": {
              "script": "termInfo=_index['text'].get('cas',_POSITIONS);wordCount=doc['text.word_count'].value;if (termInfo) {for(pos in termInfo){return (wordCount-pos.position)/wordCount}};"
            },
            "boost_mode": "sum"
          }
        }
      ]
    }
  }
}
  • и результаты:
   "hits": {
      "total": 2,
      "max_score": 1.3715843,
      "hits": [
         {
            "_index": "test",
            "_type": "test",
            "_id": "1",
            "_score": 1.3715843,
            "_source": {
               "text": "Casa Road"
            }
         },
         {
            "_index": "test",
            "_type": "test",
            "_id": "2",
            "_score": 0.8715843,
            "_source": {
               "text": "Jalan Casa"
            }
         }
      ]
   }
person Andrei Stefan    schedule 22.09.2015