Я пишу приложение Flask и использую elasticsearch.
Вот search.py
:
from flask import current_app
def query_object(index, fields, query, page, per_page, fuzziness=0):
search = current_app.elasticsearch.search(
index=index,
body={'query': {'multi_match': {'query': str(query), 'fields': fields, 'fuzziness': fuzziness, 'lenient': True}},
'from': (page - 1) * per_page, 'size': per_page}
)
ids = [int(hit['_id']) for hit in search['hits']['hits']]
return ids, search['hits']['total']['value']
Индексируется следующая модель:
class WishList(db.Model, SearchableMixin):
__searchable__ = ['first_name', 'gender', 'wants', 'needs', 'wear',
'read', 'shoe_size_category', 'shoe_type', 'sheet_size', 'additional_comments', 'time_chosen',
'age', 'shoe_sock_size', 'program_number']
id = db.Column(db.Integer, primary_key=True)
program_number = db.Column(db.String(4))
first_name = db.Column(db.String(20))
age = db.Column(db.String(10))
gender = db.Column(db.String(20))
wants = db.Column(db.String(300))
needs = db.Column(db.String(300))
wear = db.Column(db.String(300))
read = db.Column(db.String(300))
pant_dress_size = db.Column(db.String(20), default='unspecified')
shirt_blouse_size = db.Column(db.String(20), default='unspecified')
jacket_sweater_size = db.Column(db.String(20), default='unspecified')
shoe_sock_size = db.Column(db.String(20), default='unspecified')
shoe_size_category = db.Column(db.String(20), default='unspecified')
shoe_type = db.Column(db.String(50), default='unspecified')
sheet_size = db.Column(db.String(20), default='unspecified')
additional_comments = db.Column(db.Text(), nullable=True, default=None)
time_chosen = db.Column(db.String(40), nullable=True, default=None)
sponsor_id = db.Column(db.Integer, db.ForeignKey(
'user.id'), nullable=True, default=None)
drive_id = db.Column(db.Integer, db.ForeignKey(
'holiday_cheer_drive.id'), nullable=False, default=None)
Эта модель сделана доступной для поиска путем наследования от класса SearchableMixin следующим образом:
class SearchableMixin(object):
@classmethod
def search_object(cls, fields, expression, page, per_page, fuzziness=0):
ids, total = query_object(
cls.__tablename__, fields, expression, page, per_page, fuzziness=fuzziness)
if total == 0:
return cls.query.filter_by(id=0), 0
when = []
for i in range(len(ids)):
when.append((ids[i], i))
return cls.query.filter(cls.id.in_(ids)).order_by(
db.case(when, value=cls.id)), total
Когда я ищу его в настоящее время, все поля доступны для поиска и возвращают действительный результат, ЕСЛИ я не ищу с числовым значением.
Вот пример вывода для поиска, который работает, когда я говорю питону выводить значения на консоль:
Query: bob
Body of search:
{'from': 0,
'query': {'multi_match': {'fields': ['first_name',
'gender',
'wants',
'needs',
'wear',
'read',
'shoe_size_category',
'shoe_type',
'sheet_size',
'additional_comments',
'time_chosen',
'age',
'shoe_sock_size',
'program_number'],
'fuzziness': 0,
'lenient': True,
'query': 'bob'}},
'size': 10}
Python elasticsearch object:
{'took': 27, 'timed_out': False, '_shards': {'total': 1, 'successful': 1, 'skipped': 0, 'failed': 0}, 'hits': {'total': {'value': 2, 'relation': 'eq'}, 'max_score': 1.6916759, 'hits': [{'_index': 'wish_list', '_type': '_doc', '_id': '1', '_score': 1.6916759, '_source': {'first_name': 'bob', 'gender': 'male', 'wants': 'bike', 'needs': 'calculator', 'wear': 'hat', 'read': 'book', 'shoe_size_category': "men's", 'shoe_type': 'sneaker', 'sheet_size': 'unspecified', 'additional_comments': 'Likes cheese', 'time_chosen': None, 'age': '5', 'shoe_sock_size': '4', 'program_number': '215', 'mappings': {'properties': {'first_name': {'type': 'text'}, 'gender': {'type':
'text'}, 'wants': {'type': 'text'}, 'needs': {'type': 'text'}, 'wear': {'type': 'text'}, 'read': {'type': 'text'}, 'shoe_size_category': {'type': 'text'}, 'shoe_type': {'type': 'text'}, 'sheet_size': {'type': 'text'}, 'additional_comments': {'type': 'text'}, 'time_chosen': {'type': 'text'}, 'age': {'type': 'text'}, 'shoe_sock_size': {'type': 'text'}, 'program_number': {'type': 'text'}}}}}, {'_index': 'wish_list', '_type': '_doc', '_id': '9', '_score': 1.6916759, '_source': {'first_name': 'bob', 'gender': 'male', 'wants': 'bike', 'needs': 'calculator', 'wear': 'hat', 'read': 'book', 'shoe_size_category': "men's", 'shoe_type': 'sneaker', 'sheet_size': 'unspecified', 'additional_comments': 'Likes cheese', 'time_chosen': None, 'age': 5, 'shoe_sock_size': 4, 'program_number': 215, 'mappings': {'properties': {'first_name': {'type': 'text'}, 'gender': {'type': 'text'}, 'wants': {'type': 'text'}, 'needs': {'type': 'text'}, 'wear': {'type': 'text'}, 'read': {'type': 'text'}, 'shoe_size_category': {'type': 'text'}, 'shoe_type': {'type': 'text'}, 'sheet_size': {'type': 'text'}, 'additional_comments': {'type': 'text'}, 'time_chosen': {'type': 'text'}, 'age': {'type': 'text'}, 'shoe_sock_size': {'type': 'text'}, 'program_number': {'type': 'text'}}}}}]}}
А вот тот же точный запрос к тому же самому объекту, но с числовой строкой:
Query: 215
Body of search:
{'from': 0,
'query': {'multi_match': {'fields': ['first_name',
'gender',
'wants',
'needs',
'wear',
'read',
'shoe_size_category',
'shoe_type',
'sheet_size',
'additional_comments',
'time_chosen',
'age',
'shoe_sock_size',
'program_number'],
'fuzziness': 0,
'lenient': True,
'query': '215'}},
'size': 10}
Python elasticsearch object:
{'took': 18, 'timed_out': False, '_shards': {'total': 1, 'successful': 1, 'skipped': 0, 'failed': 0}, 'hits': {'total': {'value': 0, 'relation': 'eq'}, 'max_score': None, 'hits': []}}
В функцию передается строка, и все данные сохраняются как строки, но, похоже, есть какая-то ошибка типа. До того, как я добавил lenient: True
, он выдавал ошибку, говоря, что elasticsearch не может построить запрос.
Если я могу понять, как я бы сделал это с помощью REST API elasticsearch, тогда я, вероятно, смогу понять, как это сделать с помощью python.