Skip to content

Commit f5d04fc

Browse files
authored
Merge branch 'develop' into edit_post_form
2 parents a2461e2 + 49bed1e commit f5d04fc

File tree

16 files changed

+375
-24
lines changed

16 files changed

+375
-24
lines changed

.config/docker_example.yml

+2
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,8 @@ fulltextSearch:
141141
# - meilisearch
142142
# Use Meilisearch.
143143
# You need to install Meilisearch and configure.
144+
# - opensearch
145+
# 高度な検索と同様の部分一致検索になります
144146
provider: sqlLike
145147

146148
# For Meilisearch settings.

.config/example.yml

+2
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,8 @@ fulltextSearch:
223223
# - meilisearch
224224
# Use Meilisearch.
225225
# You need to install Meilisearch and configure.
226+
# - opensearch
227+
# 高度な検索と同様の部分一致検索になります
226228
provider: sqlLike
227229

228230
# For Meilisearch settings.

.github/cherrypick/test-opensearch.yml

+3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ redis:
1414
port: 56312
1515
id: aidx
1616

17+
fulltextSearch:
18+
provider: opensearch
19+
1720
opensearch:
1821
host: 127.0.0.1
1922
port: 59200

CHANGELOG_YOJO.md

+4
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,17 @@ Misskey 2025.2.0
77
### General
88
- ロックダウン機能を削除 [#650](https://github.com/yojo-art/cherrypick/pull/650)
99
- リモートユーザーの設定は反映します
10+
- Feat: リモートインスタンスのソフトウェア一覧 [#659](https://github.com/yojo-art/cherrypick/pull/659)
11+
- エンドポイント:`api/federation/remote-software`
12+
- フロントエンドでは`/about#charts` で確認できます
1013

1114
### Client
1215
- yojo-art アップデートを開くとサーバー設定が更新される問題を修正 [#651](https://github.com/yojo-art/cherrypick/pull/651)
1316
- リアクション付ける前に確認ダイアログを追加するオプション [#657](https://github.com/yojo-art/cherrypick/pull/657)
1417

1518
### Server
1619
- リモートのイベントを表示できるように [#658](https://github.com/yojo-art/cherrypick/pull/658)
20+
- 通常の検索でもOpenSearchを利用できるように [#661](https://github.com/yojo-art/cherrypick/pull/661)
1721

1822
## 1.3.1
1923
Cherrypick 4.13.0

packages/backend/src/config.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ export type Config = {
247247
pidFile: string;
248248
};
249249

250-
export type FulltextSearchProvider = 'sqlLike' | 'sqlPgroonga' | 'meilisearch';
250+
export type FulltextSearchProvider = 'sqlLike' | 'sqlPgroonga' | 'meilisearch' | 'opensearch';
251251

252252
const _filename = fileURLToPath(import.meta.url);
253253
const _dirname = dirname(_filename);

packages/backend/src/core/AdvancedSearchService.ts

+52-21
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@ import { MiUser } from '@/models/_.js';
1515
import type { NotesRepository, UsersRepository, PollVotesRepository, PollsRepository, NoteReactionsRepository, ClipNotesRepository, NoteFavoritesRepository } from '@/models/_.js';
1616
import { sqlLikeEscape } from '@/misc/sql-like-escape.js';
1717
import { CacheService } from '@/core/CacheService.js';
18+
import { DriveService } from '@/core/DriveService.js';
1819
import { QueryService } from '@/core/QueryService.js';
1920
import { IdService } from '@/core/IdService.js';
2021
import { LoggerService } from '@/core/LoggerService.js';
2122
import { isQuote, isRenote } from '@/misc/is-renote.js';
2223
import { IdentifiableError } from '@/misc/identifiable-error.js';
2324
import type Logger from '@/logger.js';
24-
import { DriveService } from './DriveService.js';
2525

2626
type OpenSearchHit = {
2727
_index: string
@@ -452,10 +452,10 @@ export class AdvancedSearchService {
452452
script: {
453453
lang: 'painless',
454454
source: 'if (ctx._source.containsKey("reactions")) {' +
455-
'if (ctx._source.reactions.stream().anyMatch(r -> r.emoji == params.emoji))' +
456-
' { ctx._source.reactions.stream().filter(r -> r.emoji == params.emoji && r.count < 32700).forEach(r -> r.count += 1); }' +
457-
' else { ctx._source.reactions.add(params.record); }' +
458-
'} else { ctx._source.reactions = new ArrayList(); ctx._source.reactions.add(params.record);}',
455+
'if (ctx._source.reactions.stream().anyMatch(r -> r.emoji == params.emoji))' +
456+
' { ctx._source.reactions.stream().filter(r -> r.emoji == params.emoji && r.count < 32700).forEach(r -> r.count += 1); }' +
457+
' else { ctx._source.reactions.add(params.record); }' +
458+
'} else { ctx._source.reactions = new ArrayList(); ctx._source.reactions.add(params.record);}',
459459
params: {
460460
emoji: opts.reaction,
461461
record: {
@@ -506,7 +506,7 @@ export class AdvancedSearchService {
506506
await this.opensearch.indices.create({
507507
index: this.opensearchNoteIndex as string,
508508
body: noteIndexBody,
509-
},
509+
},
510510
).catch((error) => {
511511
this.logger.error(error);
512512
throw error;
@@ -754,13 +754,13 @@ export class AdvancedSearchService {
754754
script: {
755755
lang: 'painless',
756756
source: 'if (ctx._source.containsKey("reactions")) {' +
757-
'for (int i = 0; i < ctx._source.reactions.length; i++) {' +
758-
' if (ctx._source.reactions[i].emoji == params.emoji) { ctx._source.reactions[i].count -= 1;' +
759-
//DBに格納されるノートのリアクションデータは数が0でも保持されるのでそれに合わせてデータを消さない
760-
//' if (ctx._source.reactions[i].count <= 0) { ctx._source.reactions.remove(i) }' +
761-
'break; }' +
762-
'}' +
763-
'}',
757+
'for (int i = 0; i < ctx._source.reactions.length; i++) {' +
758+
' if (ctx._source.reactions[i].emoji == params.emoji) { ctx._source.reactions[i].count -= 1;' +
759+
//DBに格納されるノートのリアクションデータは数が0でも保持されるのでそれに合わせてデータを消さない
760+
//' if (ctx._source.reactions[i].count <= 0) { ctx._source.reactions.remove(i) }' +
761+
'break; }' +
762+
'}' +
763+
'}',
764764
params: {
765765
emoji: emoji,
766766
},
@@ -813,10 +813,10 @@ export class AdvancedSearchService {
813813
}
814814

815815
/**
816-
* user削除時に使う
817-
* お気に入りとクリップの削除
818-
* ノートは個別で削除されるからそこで
819-
*/
816+
* user削除時に使う
817+
* お気に入りとクリップの削除
818+
* ノートは個別で削除されるからそこで
819+
*/
820820
@bindThis
821821
public async unindexUserFavorites (id: string) {
822822
this.unindexByQuery(this.favoriteIndex,
@@ -829,6 +829,33 @@ export class AdvancedSearchService {
829829
});
830830
}
831831

832+
@bindThis
833+
public async searchOrFail(me: MiUser | null, opts: {
834+
reactions?: string[] | null;
835+
reactionsExclude?: string[] | null;
836+
userId?: MiNote['userId'] | null;
837+
host?: string | null;
838+
origin?: string | null;
839+
fileOption?: string | null;
840+
visibility?: MiNote['visibility'] | null;
841+
excludeCW?: boolean;
842+
excludeReply?: boolean;
843+
excludeQuote?: boolean;
844+
sensitiveFilter?: string | null;
845+
followingFilter?: string | null;
846+
offset?: number | null;
847+
useStrictSearch?: boolean | null;
848+
wildCard?: boolean;
849+
}, pagination: {
850+
untilId?: MiNote['id'];
851+
sinceId?: MiNote['id'];
852+
limit?: number;
853+
},
854+
q?: string): Promise<MiNote[]> {
855+
if (!this.opensearch) throw new Error('OpenSearch is not available');
856+
return await this.searchNote(me, opts, pagination, q);
857+
}
858+
832859
/**
833860
* エンドポイントから呼ばれるところ
834861
*/
@@ -848,6 +875,7 @@ export class AdvancedSearchService {
848875
followingFilter?: string | null;
849876
offset?: number | null;
850877
useStrictSearch?: boolean | null;
878+
wildCard?: boolean;
851879
}, pagination: {
852880
untilId?: MiNote['id'];
853881
sinceId?: MiNote['id'];
@@ -883,6 +911,7 @@ export class AdvancedSearchService {
883911
});
884912
osFilter.bool.must.push(reactionsQuery);
885913
}
914+
886915
if (opts.reactionsExclude && 0 < opts.reactionsExclude.length) {
887916
const reactionsExcludeQuery = {
888917
nested: {
@@ -922,6 +951,7 @@ export class AdvancedSearchService {
922951
}
923952
}
924953
}
954+
925955
if (opts.origin) {
926956
if (opts.origin === 'local') {
927957
osFilter.bool.must_not.push({ exists: { field: 'userHost' } });
@@ -953,13 +983,14 @@ export class AdvancedSearchService {
953983

954984
if (q && q !== '') {
955985
if (opts.useStrictSearch) {
986+
const query = opts.wildCard ? `*${q}*` : q;
956987
osFilter.bool.must.push({
957988
bool: {
958989
should: [
959-
{ wildcard: { 'text.keyword': q } },
960-
{ wildcard: { 'cw.keyword': q } },
961-
{ wildcard: { 'pollChoices.keyword': q } },
962-
{ wildcard: { 'tags': q } },
990+
{ wildcard: { 'text.keyword': query } },
991+
{ wildcard: { 'cw.keyword': query } },
992+
{ wildcard: { 'pollChoices.keyword': query } },
993+
{ wildcard: { 'tags': query } },
963994
],
964995
minimum_should_match: 1,
965996
},

packages/backend/src/core/SearchService.ts

+10
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import type { NotesRepository } from '@/models/_.js';
1313
import { MiUser } from '@/models/_.js';
1414
import { sqlLikeEscape } from '@/misc/sql-like-escape.js';
1515
import { isUserRelated } from '@/misc/is-user-related.js';
16+
import { AdvancedSearchService } from '@/core/AdvancedSearchService.js';
1617
import { CacheService } from '@/core/CacheService.js';
1718
import { QueryService } from '@/core/QueryService.js';
1819
import { IdService } from '@/core/IdService.js';
@@ -90,6 +91,7 @@ export class SearchService {
9091
@Inject(DI.notesRepository)
9192
private notesRepository: NotesRepository,
9293

94+
private advancedSearchService: AdvancedSearchService,
9395
private cacheService: CacheService,
9496
private queryService: QueryService,
9597
private idService: IdService,
@@ -189,6 +191,14 @@ export class SearchService {
189191
case 'meilisearch': {
190192
return this.searchNoteByMeiliSearch(q, me, opts, pagination);
191193
}
194+
case 'opensearch': {
195+
return this.advancedSearchService.searchOrFail(me, {
196+
userId: opts.userId,
197+
host: opts.host,
198+
useStrictSearch: true,
199+
wildCard: true,
200+
}, pagination, q);
201+
}
192202
default: {
193203
// eslint-disable-next-line @typescript-eslint/no-unused-vars
194204
const typeCheck: never = this.provider;

packages/backend/src/server/api/endpoint-list.ts

+1
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,7 @@ export * as 'admin/unset-user-mutual-link' from './endpoints/admin/unset-user-mu
432432
export * as 'admin/full-index' from './endpoints/admin/full-index.js';
433433
export * as 'admin/recreate-index' from './endpoints/admin/recreate-index.js';
434434
export * as 'ap/fetch-outbox' from './endpoints/ap/fetch-outbox.js';
435+
export * as 'federation/remote-software' from './endpoints/federation/remote-software.js';
435436
export * as 'messaging/messages/search' from './endpoints/messaging/messages/search.js';
436437
export * as 'notes/advanced-search' from './endpoints/notes/advanced-search.js';
437438
export * as 'notifications/delete' from './endpoints/notifications/delete.js';

0 commit comments

Comments
 (0)