2015-03-20 3 views
0

Существует документ типа «человек» с двумя полями «город» и «пол», например.elasticsearch BitSet Filter или что-то еще?

person : { 
    "name" : "x", 
    "city" : "stockholm", 
    "gender" : "m" 
} 

Пример данных:

person: {name: "x", "city" : "stockholm", "gender" : "m"} 
person: {name: "y", "city" : "stockholm", "gender" : "m"} 
person: {name: "z", "city" : "stockholm", "gender" : "m"} 
person: {name: "zz", "city" : "stockholm", "gender" : "f"} 
person: {name: "xy", "city" : "uppsala", "gender" : "m"} 
person: {name: "xz", "city" : "stockholm", "gender" : "m"} 
person: {name: "yy", "city" : "uppsala", "gender" : "f"} 

Первый запрос: выбрать 2-х человек случайно, которые живут в стокгольм

size: 2, 
    "query": { 
    "function_score": { 
     "query": { 
     "term": { 
      "city": { 
      "value": "stockholm" 
      } 
     } 
     }, 
     "functions": [ 
     { 
      "random_score": { 
      "seed": 314159265359 
      } 
     } 
     ] 
    } 
    } 

Всего хитов выше запроса 5, из которых были отобраны 2 результатов в случайном порядке

possible result (As it can be random): 
person: {name: "y", "city" : "stockholm", "gender" : "m"} 
person: {name: "zz", "city" : "stockholm", "gender" : "f"} 

Второй запрос: теперь я хочу выбрать людей, у которых есть пол «м», но не был выбран по первому запросу. что-то вроде

bool : must [{ 
    term: { 
    "gender" : "m" 
    } 
}] 
must_not : [{ /*NOT SELECTED BY FIRST QUERY i.e name = y, zz */}] 

result: 
person: {name: "x", "city" : "stockholm", "gender" : "m"}   
person: {name: "z", "city" : "stockholm", "gender" : "m"} 
person: {name: "xy", "city" : "uppsala", "gender" : "m"} 
person: {name: "xz", "city" : "stockholm", "gender" : "m"} 

Возможно ли это с помощью каких-либо средств в elasticsearch? Возможно, с помощью фильтров (с использованием BitSet для быстрого доступа к идентификаторам документов) или с помощью разборки запроса?

Обратите внимание, что размер данных составляет миллионы, и если я извлекаю данные из первого запроса, что приводит к нескольким миллионам, это занимает много времени, что неприемлемо в нашем сценарии. Мне нужно только подсчет, а не фактические данные в обоих запросах.

Я не против делать это в одном запросе, если это возможно, но я не уверен, как это сделать.

+0

Вам нужен точный подсчет или примерный? – Giovanni

+0

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

+0

Поскольку это случайное значение, вам необходимо вручную ввести условия обязательного условия must_not. как «must_not»: [{"name": "y"}, {"name": "zz"}] – Varshaan

ответ

0

Я сделал простой тестовый пример с вашими данными.

Если запрос возвращает случайные данные, которые вы вынуждены сделать два запроса Первый одно возвращение п строк, вы должны принять п иды/атрибуты результата, и исключить их из второго

Второй запрос может быть что-то вроде (я написал фильтр, чтобы исключить человека с именем «х» и «ZZ»):

{ 
    "aggs":{ 
     "persons":{ 
     "filter":{ 
      "bool":{ 
       "must_not":{ 
        "term":{ 
        "name":"x" 
        } 
       }, 
       "must_not":{ 
        "term":{ 
        "name":"zz" 
        } 
       } 
      } 
     }, 
     "aggs":{ 
      "gender":{ 
       "terms":{ 
        "field":"gender" 
       } 
      } 
     } 
     } 
    } 
} 

и результаты, сгруппированных по признаку пола является

{ 
    "took": 5, 
    "timed_out": false, 
    "_shards": { 
    "total": 5, 
    "successful": 5, 
    "failed": 0 
    }, 
    "hits": { 
    "total": 7, 
    "max_score": 0, 
    "hits": [ 

    ] 
    }, 
    "aggregations": { 
    "persons": { 
     "doc_count": 5, 
     "gender": { 
     "doc_count_error_upper_bound": 0, 
     "sum_other_doc_count": 0, 
     "buckets": [ 
      { 
      "key": "m", 
      "doc_count": 4 
      }, 
      { 
      "key": "f", 
      "doc_count": 1 
      } 
     ] 
     } 
    } 
    } 
} 

Второй запрос возвращает счет по полу, исключая два результата предыдущего запроса.

Для флиртного запроса, я думаю, вам нужна другая реализация случайных. Если у вас миллион строк, и вы сначала назначаете каждому из них случайное число, а затем сортируете строки по этому номеру, это неизбежно, что потребуется много времени. Более разумным решением было бы использовать поле последовательности для каждого документа, сохраняя его, а затем генерировать два случайных числа в диапазоне [0..max вашего значения последовательности]. с двумя номерами вы можете запросить данные очень быстро и применить второй запрос. С этим решением время отклика будет намного быстрее.

+0

Я понимаю ваш ответ. Это был мой план резервного копирования, но это не чистое решение.Ключевым моментом здесь является то, что в первом запросе мне нужны случайные «n» результаты. Затем во втором запросе я хочу «НЕ ВКЛЮЧАТЬ» те «n» результаты, возвращаемые первым запросом. Как я могу выполнить пересечение, когда я не знаю, какие результаты были извлечены именно из 1-го запроса. Я мог бы получить перекрытие, или я не получу перекрытие. Надеюсь, вы понимаете мой комментарий. – Zeeshan

+0

Я не понимаю, что означает «случайное n». Вы фильтруете поле, и вы получаете счетчик для этого поля; где случайность? в указанном вами вопросе вам нужно всего лишь подсчет не всех данных. Что вы считаете? – Giovanni

+0

Результаты первого запроса могут быть случайными, и мне нужно только подмножество этого результата. Посмотрите результат первого запроса в первом запросе. Мне нужно подсчитать второй запрос, но, по моему мнению, это невозможно сделать в одном запросе, поэтому я написал два запроса. Получите случайные данные из первого запроса, передайте его во втором запросе, как-то отрицая результат первого запроса. Я уточню вопрос, чтобы сделать его более понятным. – Zeeshan