以下のことを単一クエリで実行したい
既読状態がユーザーごとに異なる場合、この情報をユーザーインデックスではなく、別のインデックス(例えば user_book
という名前で)に保存します。ユーザーと本の関連付けを管理するためのインデックスです。
ユーザー: id, name
本: id, title, author
ユーザーと本の関連:user_id, book_id, is_read
以下にそれぞれのコードを示します。
ユーザー、本、ユーザーと本の関連のインデックス作成
from elasticsearch import Elasticsearch
es = Elasticsearch()
# ユーザーのインデックス作成
es.indices.create(index='user', body={
'mappings': {
'properties': {
'id': {'type': 'integer'},
'name': {'type': 'text'}
}
}
})
# 本のインデックス作成
es.indices.create(index='book', body={
'mappings': {
'properties': {
'id': {'type': 'integer'},
'title': {'type': 'text'},
'author': {'type': 'text'}
}
}
})
# ユーザーと本の関連のインデックス作成
es.indices.create(index='user_book', body={
'mappings': {
'properties': {
'user_id': {'type': 'integer'},
'book_id': {'type': 'integer'},
'is_read': {'type': 'boolean'}
}
}
})
既読にした本のインデキシング更新:
# ユーザーと本のid、既読状態をセット
user_id = 1
book_id = 1
is_read = True
# ユーザーと本の関連情報を検索
res = es.search(index='user_book', body={
'query': {
'bool': {
'must': [
{'match': {'user_id': user_id}},
{'match': {'book_id': book_id}}
]
}
}
})
検索結果があれば更新、なければ登録
if res['hits']['hits']:
doc_id = res['hits']['hits'][0]['_id']
es.update(index='user_book', id=doc_id, body={'doc': {'is_read': is_read}})
else:
es.index(index='user_book', body={'user_id': user_id, 'book_id': book_id, 'is_read': is_read})
既読を除外して本を検索
ユーザーidと検索クエリ
user_id = 1
query = "ハリー・ポッター"
# ユーザーが既読にした本を検索
res = es.search(index='user_book', body={
'query': {
'bool': {
'must': [
{'match': {'user_id': user_id}},
{'match': {'is_read': True}}
]
}
}
})
# 既読にした本のidリストを作成
read_book_ids = [hit['_source']['book_id'] for hit in res['hits']['hits']]
# 既読にした本を除いて、クエリにマッチする本を検索
res = es.search(index='book', body={
'query': {
'bool': {
'must': {
'match': {
'title': query
}
},
'must_not': [{'ids': {'values': read_book_ids}}]
}
}
})
# 検索結果の表示
for hit in res['hits']['hits']:
print(hit['_source'])
このコードの注意点は先程と同じです。Python環境が必要で、ElasticsearchクライアントのバージョンとElasticsearchサーバーのバージョンが合っていることを確認してください。