LoginSignup
1
0

悩み:OSで複数クエリに分けずに、既読情報を考慮して検索したい。

Last updated at Posted at 2024-03-13

以下のことを単一クエリで実行したい

既読状態がユーザーごとに異なる場合、この情報をユーザーインデックスではなく、別のインデックス(例えば 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サーバーのバージョンが合っていることを確認してください。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0