Apache Solr – wyszukiwanie pełnotekstowe – inteligentna wyszukiwarka


Apache Solr – wyszukiwanie pełnotekstowe – inteligentna wyszukiwarka

Inteligentna wyszukiwarka to mechanizm który pozwala na podpowiadanie wyszukiwanych przez użytkownika słów. Wpis ten bazuje na danych które zostały zaimportowane z bazy MySQL w poprzednim wpisie dotyczącym Apache Solr – zachęcam do zapoznania się z nim:

https://javaleader.pl/2019/09/24/apache-solr-import-danych-z-uzyciem-bazy-mysql/

Tworzymy nowy projekt Spring Boota – niezbędne zależności – plik pom.xml:

<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-data-solr</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-thymeleaf</artifactId>
	</dependency>
	<dependency>
		<groupId>org.projectlombok</groupId>
		<artifactId>lombok</artifactId>
	</dependency>
	<dependency>
		<groupId>org.webjars</groupId>
		<artifactId>bootstrap</artifactId>
		<version>3.3.5</version>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
	</dependency>
</dependencies>

Plik application.properties – konfigurujemy port oraz adres pod którym dostępne jest oprogramowanie Apache Solr:

server.port           = 8089
spring.data.solr.host = http://localhost:8983/solr/

Tworzymy model – (solCoreName to nazwa core która skonfigurowana jest w Apache Solr):

@Data
@NoArgsConstructor
@AllArgsConstructor
@SolrDocument(solrCoreName = "comments")
public class Comment {

    @Id
    @Field
    private String id;

    @Field(value = "comment_content")
    private String commentContent;

    public Comment(String commentContent) {
        this.commentContent = commentContent;
    }
}

Serwis:

public interface CommentService {
    FacetPage<Comment> autocomplete(String query, Pageable pageable);
}

Implementacja serwisu:

@Service
public class CommentServiceImpl implements CommentService {

    private final CommentRepository commentRepository;

    @Autowired
    public CommentServiceImpl(CommentRepository productRepository) {
        this.commentRepository = productRepository;
    }

    @Override
    public FacetPage<Comment> autocomplete(String query, Pageable pageable) {
        if(StringUtils.isBlank(query)) {
            return new SolrResultPage<>(Collections.emptyList());
        }
        return commentRepository.findByCommentContentIgnoreCaseStartingWith(query, pageable);
    }

}

Repozytorium danych:

Faceting to metoda kategoryzacji treści w oparciu o wskazane kryterium wyszukiwania, repozytorium korzysta z adnotacji @Facet aby prawidłowo mapować zapytania do Apache Solr:

public interface CommentRepository extends SolrCrudRepository<Comment, String> {
    @Facet(fields = { "comment_content" })
    FacetPage<Comment> findByCommentContentIgnoreCaseStartingWith(String commentContent, Pageable pageable);
}

oraz kontroler:

@Slf4j
@Controller
public class CommentController {

    private final CommentService commentService;

    @Autowired
    public CommentController(CommentService commentService) {
        this.commentService = commentService;
    }

    @RequestMapping(value = "/autocomplete", produces = "application/json")
    public @ResponseBody
    Set<String> autoComplete(@RequestParam("term") String query,
                             @PageableDefault(page = 0, size = 1) Pageable pageable) {

        if (!StringUtils.hasText(query)) {
            return Collections.emptySet();
        }

        FacetPage<Comment> result = commentService.autocomplete(query, pageable);

        Set<String> titles = new LinkedHashSet<>();
        for (Page<FacetFieldEntry> page : result.getFacetResultPages()) {
            for (FacetFieldEntry entry : page) {
                Optional<String> entryValue = Optional.ofNullable(entry.getValue());
                if(entryValue.isPresent() && entryValue.get().contains(query.toLowerCase())){
                    titles.add(StringUtils.capitalize(entryValue.get()));
                }
            }
        }
        return titles;
    }

    @GetMapping("/")
    public String homeSearchPage(){
        return "index";
    }
}

Teraz czas na wyszukiwarkę – plik ./resources/templates/index.html:

<body>
    <input type="text" id="comment_content" class="form-control" placeholder="Comment content here..."/>
</body>

W pliku ./resources/static/js/script.js zamieszczamy kod java script który odpowiedzialny będzie za autouzupełnianie formularza wyszukiwarki w oparciu o dane pobierane z Apache Solr:

$(function() {
    $("#comment_content")
        .autocomplete(
            {
                source : 'http://localhost:8089/autocomplete',
                minLength : 1,
            });
});

Po wejściu na główną stronę aplikacji i wpisaniu w formularzu dwóch pierwszych liter automatycznie pojawią się podpowiedzi zaczerpnięte z użyciem Apache Solr:

Warto dodać wpis css:

<style>
	.ui-helper-hidden-accessible {
		border: 0;
		clip: rect(0 0 0 0);
		height: 1px;
		margin: -1px;
		overflow: hidden;
		padding: 0;
		position: absolute;
		width: 1px;
	}
</style>

aby uniknąć zbędnych komunikatów:

Kod źródłowy do wglądu na GitHub!

Jeśli chcesz uzyskać dostęp do GitHuba na 30 dni i pobrać kod źródłowy wyślij smsa o treśći DOSTEP.EDUSESSION na numer 7943. Tyle wiedzy a koszt to tylko 9 PLN (11.07 PLN z VAT).





Leave a comment

Your email address will not be published.


*