# Как правильно сортировать выдачу?

**URL:** <https://discuss.elastic.co/t/topic/35729>\
**Category:** Вопросы на русском языке\
**Created:** [November 27, 2015, 9:35am UTC](https://discuss.elastic.co/t/topic/35729 "2015-11-27T09:35:25Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![stanleer](https://avatars.discourse-cdn.com/v4/letter/s/d07c76/32.png) [@stanleer](https://discuss.elastic.co/u/stanleer)\
**Post date:** [November 27, 2015, 9:35am UTC](https://discuss.elastic.co/t/topic/35729/1 "2015-11-27T09:35:25Z")

</div>

Использую прослойку elastica

Есть индекс с уличами и номерами домов.

Без указания параметров все ищется нормально.

```
$resultSet = $search->addIndex($this->_index)
    ->addType('street')
    ->search($text."*")
;

```

Как пытаюсь указать параметры ничего не находит.

```
     $query = new \Elastica\Query\Builder('{
        "query" : {
            "term" : { "street_name" : "'.$text.'" }
        },
        "sort": { "street_name": { "order": "desc" }}
    }');

    $query = new \Elastica\Query($query->toArray());

    $resultSet = $search->addIndex($this->_index)
        ->addType('street')
        ->search($query)
    ;

```

Подскажите как правильно сортировать выдачу?

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [December 2, 2015, 5:47pm UTC](https://discuss.elastic.co/t/topic/35729/2 "2015-12-02T17:47:28Z")

</div>

Проблема не в сортировке - проблема в запросе. Попробуйте использовать запрос `match` вместо `term`. Запрос `term` не выполняет анализ запросов и поэтому может не вернуть ожидаемые результаты.

---

<div class="post-metadata">

**Author:** ![stanleer](https://avatars.discourse-cdn.com/v4/letter/s/d07c76/32.png) [@stanleer](https://discuss.elastic.co/u/stanleer)\
**Post date:** [December 3, 2015, 8:42am UTC](https://discuss.elastic.co/t/topic/35729/3 "2015-12-03T08:42:12Z")

</div>

Спасибо за ответ, буду пробовать.

---

<div class="post-metadata">

**Author:** ![stanleer](https://avatars.discourse-cdn.com/v4/letter/s/d07c76/32.png) [@stanleer](https://discuss.elastic.co/u/stanleer)\
**Post date:** [December 4, 2015, 6:51pm UTC](https://discuss.elastic.co/t/topic/35729/4 "2015-12-04T18:51:28Z")

</div>

Ничего не получилось.

Давай начем тогда с начала.

Есть два поля в документе и надо найти документ, который совпадает по этим двум полям.

пробовал такой запрос, ни к чему не привел

```
{
    "query": {
        "bool": {
            "should": [
                { "match": { "id": "id" }},
                { "match": { "name": "name" }}
            ]
        }
    }
}

```

Так же не понятно ка искать если одно поле заполняется частично, реализуется механизм подсказок.

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [December 4, 2015, 6:53pm UTC](https://discuss.elastic.co/t/topic/35729/5 "2015-12-04T18:53:37Z")

</div>

Как выглядит документ и схема индекса?

---

<div class="post-metadata">

**Author:** ![stanleer](https://avatars.discourse-cdn.com/v4/letter/s/d07c76/32.png) [@stanleer](https://discuss.elastic.co/u/stanleer)\
**Post date:** [December 4, 2015, 7:16pm UTC](https://discuss.elastic.co/t/topic/35729/6 "2015-12-04T19:16:17Z")

</div>

не вставляется с нормальной разметкой (

{  
"geo" : {  
"mappings" : {  
"street" : {  
"properties" : {  
"parentguid" : {  
"type" : "string"  
},  
"postalcode" : {  
"type" : "string"  
},  
"street\_name" : {  
"type" : "string"  
},  
"street\_shortname" : {  
"type" : "string"  
}  
}  
},  
"city" : {  
"properties" : {  
"city\_id" : {  
"type" : "string"  
},  
"name" : {  
"type" : "string"  
},  
"region\_id" : {  
"type" : "string"  
}  
}  
}  
}  
}  
}

в одном типе ищу по точному совпадению с parentguid и не полному street\_name

документ создается так

`$document = new \Elastica\Document($street->code, ['parentguid' => $street->parentguid, 'street_shortname' => $street->shortname, 'street_name' => $street->formalname, 'postalcode' => $street->postalcode]);`

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [December 5, 2015, 12:05am UTC](https://discuss.elastic.co/t/topic/35729/7 "2015-12-05T00:05:56Z")

</div>

Как то так?

```auto
curl -XDELETE "localhost:9200/test?pretty"
curl -XPUT "localhost:9200/test?pretty" -d '{
  "settings": {
    "number_of_replicas": 0,
    "number_of_shards": 1
  },
  "mappings" : {
    "street" : {
      "properties" : {
        "parentguid" : {
          "type" : "string",
          "index": "not_analyzed"
        },
        "postalcode" : {
          "type" : "string",
          "index": "not_analyzed"
        },
        "street_name" : {
          "type" : "string"
        },
        "street_shortname" : {
          "type" : "string"
        }
      }
    },
    "city" : {
      "properties" : {
        "city_id" : {
          "type" : "string",
          "index": "not_analyzed"
        },
        "name" : {
          "type" : "string"
        },
        "region_id" : {
          "type" : "string",
          "index": "not_analyzed"
        }
      }
    }
  }
}'
curl -XPUT "localhost:9200/test/street/1?pretty" -d '{
  "parentguid": "12345-67890",
  "street_name": "Main St."
}'
curl -XPOST "localhost:9200/test/_refresh?pretty"
curl -XGET "localhost:9200/test/street/_search?pretty" -d '{
    "query": {
        "bool": {
            "must": [
                { "match": { "parentguid": "12345-67890" }},
                { "match": { "street_name": "main" }}
            ]
        }
    }
}'

```

---

<div class="post-metadata">

**Author:** ![stanleer](https://avatars.discourse-cdn.com/v4/letter/s/d07c76/32.png) [@stanleer](https://discuss.elastic.co/u/stanleer)\
**Post date:** [December 7, 2015, 9:52am UTC](https://discuss.elastic.co/t/topic/35729/8 "2015-12-07T09:52:24Z")

</div>

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

попробовал твой вариант, работает, может все из-за русской морфологии?

еще вопрос - можно ли как то журналировать get post запросы для отладки?

---

<div class="post-metadata">

**Author:** ![stanleer](https://avatars.discourse-cdn.com/v4/letter/s/d07c76/32.png) [@stanleer](https://discuss.elastic.co/u/stanleer)\
**Post date:** [December 7, 2015, 10:24am UTC](https://discuss.elastic.co/t/topic/35729/9 "2015-12-07T10:24:09Z")

</div>

хотя нет, твой вариант тоже не рабочий

если ввести "street\_name": "mai", то не найдет

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [December 7, 2015, 2:58pm UTC](https://discuss.elastic.co/t/topic/35729/10 "2015-12-07T14:58:36Z")

</div>

> [@stanleer](#):
>
> если ввести "street\_name": "mai", то не найдет

Вы нигде не упоминали, что Вам необходим поиск по подстроке. Поиск по подстроке - это уже совсем другая история.

Посмотрите [соседний топик](https://discuss.elastic.co/t/topic/36413/5). Я там привел пример поиска по подстрокам.

---

<div class="post-metadata">

**Author:** ![stanleer](https://avatars.discourse-cdn.com/v4/letter/s/d07c76/32.png) [@stanleer](https://discuss.elastic.co/u/stanleer)\
**Post date:** [December 7, 2015, 3:00pm UTC](https://discuss.elastic.co/t/topic/35729/11 "2015-12-07T15:00:24Z")

</div>

Возможно я не правилно описал ситуацию

> в одном типе ищу по точному совпадению с parentguid и не полному street\_name

по неполному совпадению в street\_name и имелос ввиду.

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [December 7, 2015, 3:03pm UTC](https://discuss.elastic.co/t/topic/35729/12 "2015-12-07T15:03:05Z")

</div>

Тогда пример с edgeNGram в соседнем топике должен для вас работать.

---

<div class="post-metadata">

**Author:** ![stanleer](https://avatars.discourse-cdn.com/v4/letter/s/d07c76/32.png) [@stanleer](https://discuss.elastic.co/u/stanleer)\
**Post date:** [December 7, 2015, 3:29pm UTC](https://discuss.elastic.co/t/topic/35729/13 "2015-12-07T15:29:30Z")

</div>

читал в интернете, что для русской морфологии ставятся плагины  
особо разницы не заметил, это не актуально?

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [December 7, 2015, 4:03pm UTC](https://discuss.elastic.co/t/topic/35729/14 "2015-12-07T16:03:05Z")

</div>

Морфология не актуальна для названий улиц, и даже может навредить. Когда Вы ищете по тексту, и в поиске задан термин `повелецкий`, то с помощью русской морфологии можно будет найти и текст со словам `павелецком`, и текст со словом `павелецкая`.

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

---

<div class="post-metadata">

**Author:** ![stanleer](https://avatars.discourse-cdn.com/v4/letter/s/d07c76/32.png) [@stanleer](https://discuss.elastic.co/u/stanleer)\
**Post date:** [February 10, 2016, 12:54pm UTC](https://discuss.elastic.co/t/topic/35729/15 "2016-02-10T12:54:24Z")

</div>

Снова возвращаюсь к этому вопросу

```auto
$mapping = [
			'code' => [
				'type' => 'string',
				'index' => 'not_analyzed'
			],
			'parentguid' => [
				'type' => 'string',
				'index' => 'not_analyzed'
			],
			'postalcode' => [
				'type' => 'string',
				'index' => 'not_analyzed'
			],
			'street_shortname' => [
				'type' => 'string',
				'index' => 'not_analyzed'
			],
			'street_name' => [
				'type' => 'string',
				'analyzer' => 'ngram_index_analyzer',
				'search_analyzer' => 'ngram_search_analyzer'
			],
			'full_name' => [
				'type' => 'string',
				'index' => 'not_analyzed'
			]
		];

```

index

```auto
			'number_of_shards' => 1,
			'number_of_replicas' => 0,
			'analysis' => [
				'analyzer' => [
					'ngram_index_analyzer' => [
						'tokenizer' => 'standard',
						'filter' => ['lowercase', 'ngram']
					],
					'ngram_search_analyzer' => [
						'tokenizer' => 'standard',
						'filter' => ['lowercase']
					],
				],
				'filter' => [
					'ngram' => [
						'type' => 'edgeNGram',
						'min_gram' => 3,
						'max_gram' => 50
					]
				]
			]

```

и сам запрос

```auto
            "query": {
                "bool": {
                    "must": [
                        { "match": { "parentguid": "'.$parentguid.'" }},
                        { "match": { "street_name": "'.$query.'" }}
                    ]
                }
            }

```

при поиске улицы: кузнецкий мост  
выдает Кузнецкий Мост и Богатырский Мост

при поиске улицы зацепенский вал выдает что только можно где было вхождение

как организовать нормальный поиск без левых выдач?

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [February 10, 2016, 2:06pm UTC](https://discuss.elastic.co/t/topic/35729/16 "2016-02-10T14:06:06Z")

</div>

> [@stanleer](#):
>
> как организовать нормальный поиск без левых выдач?

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

---

<div class="post-metadata">

**Author:** ![stanleer](https://avatars.discourse-cdn.com/v4/letter/s/d07c76/32.png) [@stanleer](https://discuss.elastic.co/u/stanleer)\
**Post date:** [February 10, 2016, 2:12pm UTC](https://discuss.elastic.co/t/topic/35729/17 "2016-02-10T14:12:09Z")

</div>

Я пытаюсь сделать систему подсказок как в яндкес или гугл картах

там же не выводится по искомой фразе еще много чего нерелеватного

если я набираю последовательно фразу Кузнецкий Мост

Набирав кузнецкий выдает Кузнецкий Мост  
если дописываю мост уже выдает и Кузнецкий Мост и Богатырский Мост  
разве это нормально?

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [February 10, 2016, 3:01pm UTC](https://discuss.elastic.co/t/topic/35729/18 "2016-02-10T15:01:01Z")

</div>

> [@stanleer](#):
>
> разве это нормально?

Если вам важно совпадение по слову "мост", то это вполне нормально, тем более, что кузнецкий мост появляется в результатах перед богатырским. Если вам необходимо совпадение по все словам, которые появляются в запросе, то вам надо переключится на другой режим в запросе match. Например с использованием оператора `and`, если вам важно совпадение всех слов в запросе

```auto
"match": {
    "street_name": {
        "query": "кузнецкий мост",
        "operator" : "and"
    }
}

```

Или с использованием `match_phrase` если важен порядок слов:

```auto
"match_phrase": {
    "street_name": {
        "query": "Кузнецкий Мост"
    }
}

```

Но при этом `кузнецкий мо` вам больше ничего возвращать не будет, потому, что у вас n-gram начинаются с 3, а нужно, чтобы они начинались с 1.

Вариантов много. Надо только точно определиться, что является "нормальным" для вас. И, главное, не подходить к elasticsearch, как к какому-то магическому существу, которое может залезть к вам в голову и точно определить, что вы хотите найти. Тут никакой магии нет - все дело в простом совпадении генерируемых токенов при запросе и индексировании. И контроль над тем, как эти токены генерируются - в ваших руках. Если вы не хотите этот контроль, то лучше использовать более простые средства - анализатор `standard` и запрос `match_phrase_prefix`.

---

<div class="post-metadata">

**Author:** ![stanleer](https://avatars.discourse-cdn.com/v4/letter/s/d07c76/32.png) [@stanleer](https://discuss.elastic.co/u/stanleer)\
**Post date:** [February 10, 2016, 3:17pm UTC](https://discuss.elastic.co/t/topic/35729/19 "2016-02-10T15:17:16Z")

</div>

С operator стало все яснее, еще пробую другие варинаты.  
Про минимальный лимит ngram вылетело из головы вообще )

Мне кажется если бы вы реализовали механизм запросов через sql было бы удобнее и понятнее.  
Многое не понятно новичку, тк тут совсем другая идеология.  
В том же sphinx все через sql и довольно быстро можно освоиться, с sql то все знакомы )

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [February 10, 2016, 11:30pm UTC](https://discuss.elastic.co/t/topic/35729/20 "2016-02-10T23:30:09Z")

</div>

> [@stanleer](#):
>
> тк тут совсем другая идеология.

Так в этом-то и все дело! Если бы мы реализовали механизм запросов через sql, то пользователи бы стали пользоваться elasticsearch как реляционной базой, и ни к чему хорошему это бы не привело. Elasticsearch это поисковый движок, который использует совсем другие модели данных, которые базируются на совсем других математических моделях и алгоритмах, и поэтому он требует иного подхода к моделированию данных и построению запросов.

[Next page](https://discuss.elastic.co/t/topic/35729.md?page=2)
